Line 1... |
Line 1... |
/* stats.c -- Various statistics about instruction scheduling etc.
|
/* stats.c -- Various statistics about instruction scheduling etc.
|
|
|
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
|
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
|
|
Copyright (C) 2008 Embecosm Limited
|
|
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
|
|
This program is free software; you can redistribute it and/or modify
|
This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#include "config.h"
|
This program is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the Free
|
|
Software Foundation; either version 3 of the License, or (at your option)
|
|
any later version.
|
|
|
#ifdef HAVE_INTTYPES_H
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
#include <inttypes.h>
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
#endif
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
more details.
|
|
|
|
You should have received a copy of the GNU General Public License along
|
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
/* This program is commented throughout in a fashion suitable for processing
|
|
with Doxygen. */
|
|
|
|
|
|
/* Autoconf and/or portability configuration */
|
|
#include "config.h"
|
#include "port.h"
|
#include "port.h"
|
#include "arch.h"
|
|
#include "abstract.h"
|
/* Package includes */
|
|
#include "stats.h"
|
#include "sim-config.h"
|
#include "sim-config.h"
|
#include "spr_defs.h"
|
#include "icache-model.h"
|
#include "opcode/or32.h"
|
#include "spr-defs.h"
|
#include "execute.h"
|
#include "execute.h"
|
#include "sprs.h"
|
|
#include "debug.h"
|
|
#include "stats.h"
|
|
#include "icache_model.h"
|
|
|
|
struct branchstat {
|
|
|
#define DSTATS_LEN 3000
|
|
#define SSTATS_LEN 300
|
|
#define FSTATS_LEN 200
|
|
#define RAW_RANGE 1000
|
|
|
|
/* Used by safe division - increment divisor by one if it is zero */
|
|
#define SD(X) (X != 0 ? X : 1)
|
|
|
|
struct branchstat
|
|
{
|
int taken;
|
int taken;
|
int nottaken;
|
int nottaken;
|
int forward;
|
int forward;
|
int backward;
|
int backward;
|
};
|
};
|
|
|
/* See also enum insn_type in abstract.h */
|
/*! @see also enum insn_type in abstract.h */
|
const char func_unit_str[30][30] = { "unknown", "exception", "arith", "shift", "compare",
|
static const char func_unit_str[30][30] = {
|
"branch", "jump", "load", "store", "movimm", "move", "extend", "nop", "mac" };
|
"unknown",
|
|
"exception",
|
struct dstats_entry dstats[DSTATS_LEN]; /* dependency stats */
|
"arith",
|
struct sstats_entry sstats[SSTATS_LEN]; /* single stats */
|
"shift",
|
struct fstats_entry fstats[FSTATS_LEN]; /* functional units stats */
|
"compare",
|
struct mstats_entry or1k_mstats = {0}; /* misc units stats */
|
"branch",
|
struct cachestats_entry ic_stats = {0}; /* instruction cache stats */
|
"jump",
|
struct cachestats_entry dc_stats = {0}; /* data cache stats */
|
"load",
|
struct immustats_entry immu_stats = {0}; /* insn mmu stats */
|
"store",
|
struct dmmustats_entry dmmu_stats = {0}; /* data mmu stats */
|
"movimm",
|
struct raw_stats raw_stats; /* RAW hazard stats */
|
"move",
|
|
"extend",
|
|
"nop",
|
|
"mac"
|
|
};
|
|
|
|
struct dstats_entry
|
|
{
|
|
int insn1;
|
|
int insn2;
|
|
int cnt_dynamic;
|
|
int depend;
|
|
}; /*!< double stats */
|
|
|
|
struct sstats_entry
|
|
{
|
|
int insn;
|
|
int cnt_dynamic;
|
|
}; /*!< single stats */
|
|
|
|
struct fstats_entry
|
|
{
|
|
enum insn_type insn1;
|
|
enum insn_type insn2;
|
|
int cnt_dynamic;
|
|
int depend;
|
|
}; /*!< functional units stats */
|
|
|
void addsstats(int item, int cnt_dynamic)
|
struct raw_stats
|
|
{
|
|
int reg[64];
|
|
int range[RAW_RANGE];
|
|
}; /*!< RAW hazard stats */
|
|
|
|
/* Globally visible statistics data. Renamed mstats to or1k_mstats because Mac
|
|
OS X has a lib function called mstats */
|
|
struct mstats_entry or1k_mstats = { 0 }; /*!< misc units stats */
|
|
struct cachestats_entry ic_stats = { 0 }; /*!< instruction cache stats */
|
|
struct cachestats_entry dc_stats = { 0 }; /*!< data cache stats */
|
|
struct immustats_entry immu_stats = { 0 }; /*!< insn MMU stats */
|
|
struct dmmustats_entry dmmu_stats = { 0 }; /*!< data MMU stats */
|
|
|
|
/* Statistics data strutures used just here */
|
|
static struct dstats_entry dstats[DSTATS_LEN]; /*!< dependency stats */
|
|
static struct sstats_entry sstats[SSTATS_LEN]; /*!< single stats */
|
|
static struct fstats_entry fstats[FSTATS_LEN]; /*!< func units stats */
|
|
static struct raw_stats raw_stats; /*!< RAW hazard stats */
|
|
|
|
|
|
void
|
|
addsstats (int item, int cnt_dynamic)
|
{
|
{
|
int i = 0;
|
int i = 0;
|
|
|
while(sstats[i].insn != item && sstats[i].insn >= 0 && i < SSTATS_LEN) i++;
|
while (sstats[i].insn != item && sstats[i].insn >= 0 && i < SSTATS_LEN)
|
|
i++;
|
|
|
if (i >= SSTATS_LEN - 1) return;
|
if (i >= SSTATS_LEN - 1)
|
|
return;
|
|
|
if (sstats[i].insn >= 0) {
|
if (sstats[i].insn >= 0)
|
|
{
|
sstats[i].cnt_dynamic += cnt_dynamic;
|
sstats[i].cnt_dynamic += cnt_dynamic;
|
} else {
|
}
|
|
else
|
|
{
|
sstats[i].insn = item;
|
sstats[i].insn = item;
|
sstats[i].cnt_dynamic = cnt_dynamic;
|
sstats[i].cnt_dynamic = cnt_dynamic;
|
}
|
}
|
}
|
}
|
|
|
void adddstats(int item1, int item2, int cnt_dynamic, int depend)
|
void
|
|
adddstats (int item1, int item2, int cnt_dynamic, int depend)
|
{
|
{
|
int i = 0;
|
int i = 0;
|
|
|
while((dstats[i].insn1 != item1 || dstats[i].insn2 != item2) && (i < DSTATS_LEN) && dstats[i].insn1 >= 0) i++;
|
while ((dstats[i].insn1 != item1 || dstats[i].insn2 != item2)
|
|
&& (i < DSTATS_LEN) && dstats[i].insn1 >= 0)
|
|
i++;
|
|
|
if (i >= DSTATS_LEN - 1) return;
|
if (i >= DSTATS_LEN - 1)
|
|
return;
|
|
|
if (dstats[i].insn1 >= 0) {
|
if (dstats[i].insn1 >= 0)
|
|
{
|
dstats[i].cnt_dynamic += cnt_dynamic;
|
dstats[i].cnt_dynamic += cnt_dynamic;
|
dstats[i].depend += depend;
|
dstats[i].depend += depend;
|
} else {
|
}
|
|
else
|
|
{
|
dstats[i].insn1 = item1;
|
dstats[i].insn1 = item1;
|
dstats[i].insn2 = item2;
|
dstats[i].insn2 = item2;
|
dstats[i].cnt_dynamic = cnt_dynamic;
|
dstats[i].cnt_dynamic = cnt_dynamic;
|
dstats[i].depend = depend;
|
dstats[i].depend = depend;
|
}
|
}
|
}
|
}
|
|
|
void addfstats(enum insn_type item1, enum insn_type item2, int cnt_dynamic, int depend)
|
void
|
|
addfstats (enum insn_type item1, enum insn_type item2, int cnt_dynamic,
|
|
int depend)
|
{
|
{
|
int i = 0;
|
int i = 0;
|
|
|
while(((fstats[i].insn1 != item1) || (fstats[i].insn2 != item2)) &&
|
while(((fstats[i].insn1 != item1) || (fstats[i].insn2 != item2)) &&
|
(fstats[i].insn1 != it_unknown) &&
|
(fstats[i].insn1 != it_unknown) && (i < FSTATS_LEN))
|
(i < FSTATS_LEN))
|
|
i++;
|
i++;
|
|
|
if (i >= FSTATS_LEN - 1) return;
|
if (i >= FSTATS_LEN - 1)
|
|
return;
|
|
|
if ((fstats[i].insn1 == item1) &&
|
if ((fstats[i].insn1 == item1) && (fstats[i].insn2 == item2))
|
(fstats[i].insn2 == item2)) {
|
{
|
fstats[i].cnt_dynamic += cnt_dynamic;
|
fstats[i].cnt_dynamic += cnt_dynamic;
|
fstats[i].depend += depend;
|
fstats[i].depend += depend;
|
}
|
}
|
else {
|
else
|
|
{
|
fstats[i].insn1 = item1;
|
fstats[i].insn1 = item1;
|
fstats[i].insn2 = item2;
|
fstats[i].insn2 = item2;
|
fstats[i].cnt_dynamic = cnt_dynamic;
|
fstats[i].cnt_dynamic = cnt_dynamic;
|
fstats[i].depend = depend;
|
fstats[i].depend = depend;
|
}
|
}
|
}
|
}
|
|
|
void initstats()
|
void
|
|
initstats ()
|
{
|
{
|
int i;
|
int i;
|
memset(sstats, 0, sizeof(sstats));
|
memset(sstats, 0, sizeof(sstats));
|
for (i = 0; i < SSTATS_LEN; i++)
|
for (i = 0; i < SSTATS_LEN; i++)
|
sstats[i].insn = -1;
|
sstats[i].insn = -1;
|
Line 133... |
Line 203... |
memset(&ic_stats, 0, sizeof(ic_stats));
|
memset(&ic_stats, 0, sizeof(ic_stats));
|
memset(&dc_stats, 0, sizeof(dc_stats));
|
memset(&dc_stats, 0, sizeof(dc_stats));
|
memset(&raw_stats, 0, sizeof(raw_stats));
|
memset(&raw_stats, 0, sizeof(raw_stats));
|
}
|
}
|
|
|
void printotherstats(int which)
|
static void
|
|
printotherstats (int which)
|
{
|
{
|
PRINTF ("\n");
|
PRINTF ("\n");
|
if (config.bpb.enabled) {
|
if (config.bpb.enabled)
|
|
{
|
struct branchstat bf;
|
struct branchstat bf;
|
struct branchstat bnf;
|
struct branchstat bnf;
|
long bf_all, bnf_all;
|
long bf_all, bnf_all;
|
bf.taken = or1k_mstats.bf[1][0] + or1k_mstats.bf[1][1];
|
bf.taken = or1k_mstats.bf[1][0] + or1k_mstats.bf[1][1];
|
bf.nottaken = or1k_mstats.bf[0][0] + or1k_mstats.bf[0][1];
|
bf.nottaken = or1k_mstats.bf[0][0] + or1k_mstats.bf[0][1];
|
Line 152... |
Line 224... |
bnf.nottaken = or1k_mstats.bnf[0][0] + or1k_mstats.bf[0][1];
|
bnf.nottaken = or1k_mstats.bnf[0][0] + or1k_mstats.bf[0][1];
|
bnf.forward = or1k_mstats.bnf[0][1] + or1k_mstats.bf[1][1];
|
bnf.forward = or1k_mstats.bnf[0][1] + or1k_mstats.bf[1][1];
|
bnf.backward = or1k_mstats.bnf[0][0] + or1k_mstats.bf[1][0];
|
bnf.backward = or1k_mstats.bnf[0][0] + or1k_mstats.bf[1][0];
|
bnf_all = bnf.forward + bnf.backward;
|
bnf_all = bnf.forward + bnf.backward;
|
|
|
PRINTF("bnf: %d (%ld%%) taken,", bf.taken, (bf.taken * 100) / SD(bf_all));
|
PRINTF ("bnf: %d (%ld%%) taken,", bf.taken,
|
PRINTF(" %d (%ld%%) not taken,", bf.nottaken, (bf.nottaken * 100) / SD(bf_all));
|
(bf.taken * 100) / SD (bf_all));
|
PRINTF(" %d (%ld%%) forward,", bf.forward, (bf.forward * 100) / SD(bf_all));
|
PRINTF (" %d (%ld%%) not taken,", bf.nottaken,
|
PRINTF(" %d (%ld%%) backward\n", bf.backward, (bf.backward * 100) / SD(bf_all));
|
(bf.nottaken * 100) / SD (bf_all));
|
PRINTF("bf: %d (%ld%%) taken,", bnf.taken, (bnf.taken * 100) / SD(bnf_all));
|
PRINTF (" %d (%ld%%) forward,", bf.forward,
|
PRINTF(" %d (%ld%%) not taken,", bnf.nottaken, (bnf.nottaken * 100) / SD(bnf_all));
|
(bf.forward * 100) / SD (bf_all));
|
PRINTF(" %d (%ld%%) forward,", bnf.forward, (bnf.forward * 100) / SD(bnf_all));
|
PRINTF (" %d (%ld%%) backward\n", bf.backward,
|
PRINTF(" %d (%ld%%) backward\n", bnf.backward, (bnf.backward * 100) / SD(bnf_all));
|
(bf.backward * 100) / SD (bf_all));
|
|
PRINTF ("bf: %d (%ld%%) taken,", bnf.taken,
|
PRINTF("StaticBP bnf(%s): correct %ld%%\n", config.bpb.sbp_bnf_fwd ? "forward" : "backward",
|
(bnf.taken * 100) / SD (bnf_all));
|
(or1k_mstats.bnf[0][config.bpb.sbp_bnf_fwd] * 100) / SD(bnf_all));
|
PRINTF (" %d (%ld%%) not taken,", bnf.nottaken,
|
PRINTF("StaticBP bf(%s): correct %ld%%\n", config.bpb.sbp_bf_fwd ? "forward" : "backward",
|
(bnf.nottaken * 100) / SD (bnf_all));
|
(or1k_mstats.bnf[1][config.bpb.sbp_bf_fwd] * 100) / SD(bf_all));
|
PRINTF (" %d (%ld%%) forward,", bnf.forward,
|
PRINTF("BPB: hit %d (correct %d%%), miss %d\n", or1k_mstats.bpb.hit, (or1k_mstats.bpb.correct * 100) / SD(or1k_mstats.bpb.hit), or1k_mstats.bpb.miss);
|
(bnf.forward * 100) / SD (bnf_all));
|
} else
|
PRINTF (" %d (%ld%%) backward\n", bnf.backward,
|
|
(bnf.backward * 100) / SD (bnf_all));
|
|
|
|
PRINTF ("StaticBP bnf(%s): correct %ld%%\n",
|
|
config.bpb.sbp_bnf_fwd ? "forward" : "backward",
|
|
(or1k_mstats.bnf[0][config.bpb.sbp_bnf_fwd] * 100) /
|
|
SD (bnf_all));
|
|
PRINTF ("StaticBP bf(%s): correct %ld%%\n",
|
|
config.bpb.sbp_bf_fwd ? "forward" : "backward",
|
|
(or1k_mstats.bnf[1][config.bpb.sbp_bf_fwd] * 100) /
|
|
SD (bf_all));
|
|
PRINTF ("BPB: hit %d (correct %d%%), miss %d\n", or1k_mstats.bpb.hit,
|
|
(or1k_mstats.bpb.correct * 100) / SD (or1k_mstats.bpb.hit),
|
|
or1k_mstats.bpb.miss);
|
|
}
|
|
else
|
PRINTF("BPB simulation disabled. Enable it to see BPB analysis\n");
|
PRINTF("BPB simulation disabled. Enable it to see BPB analysis\n");
|
|
|
if (config.bpb.btic) {
|
if (config.bpb.btic)
|
PRINTF("BTIC: hit %d(%d%%), miss %d\n", or1k_mstats.btic.hit, (or1k_mstats.btic.hit * 100) / SD(or1k_mstats.btic.hit + or1k_mstats.btic.miss), or1k_mstats.btic.miss);
|
{
|
} else
|
PRINTF ("BTIC: hit %d(%d%%), miss %d\n", or1k_mstats.btic.hit,
|
|
(or1k_mstats.btic.hit * 100) / SD (or1k_mstats.btic.hit +
|
|
or1k_mstats.btic.miss),
|
|
or1k_mstats.btic.miss);
|
|
}
|
|
else
|
PRINTF("BTIC simulation disabled. Enabled it to see BTIC analysis\n");
|
PRINTF("BTIC simulation disabled. Enabled it to see BTIC analysis\n");
|
|
|
if(ic_state->enabled) {
|
if (ic_state->enabled)
|
PRINTF("IC read: hit %d(%d%%), miss %d\n", ic_stats.readhit, (ic_stats.readhit * 100) / SD(ic_stats.readhit + ic_stats.readmiss), ic_stats.readmiss);
|
{
|
} else
|
PRINTF ("IC read: hit %d(%d%%), miss %d\n", ic_stats.readhit,
|
|
(ic_stats.readhit * 100) / SD (ic_stats.readhit +
|
|
ic_stats.readmiss),
|
|
ic_stats.readmiss);
|
|
}
|
|
else
|
PRINTF("No ICache. Enable it to see IC results.\n");
|
PRINTF("No ICache. Enable it to see IC results.\n");
|
|
|
if (config.dc.enabled) {
|
if (config.dc.enabled)
|
PRINTF("DC read: hit %d(%d%%), miss %d\n", dc_stats.readhit, (dc_stats.readhit * 100) / SD(dc_stats.readhit + dc_stats.readmiss), dc_stats.readmiss);
|
{
|
PRINTF("DC write: hit %d(%d%%), miss %d\n", dc_stats.writehit, (dc_stats.writehit * 100) / SD(dc_stats.writehit + dc_stats.writemiss), dc_stats.writemiss);
|
PRINTF ("DC read: hit %d(%d%%), miss %d\n", dc_stats.readhit,
|
} else
|
(dc_stats.readhit * 100) / SD (dc_stats.readhit +
|
|
dc_stats.readmiss),
|
|
dc_stats.readmiss);
|
|
PRINTF ("DC write: hit %d(%d%%), miss %d\n", dc_stats.writehit,
|
|
(dc_stats.writehit * 100) / SD (dc_stats.writehit +
|
|
dc_stats.writemiss),
|
|
dc_stats.writemiss);
|
|
}
|
|
else
|
PRINTF("No DCache. Enable it to see DC results.\n");
|
PRINTF("No DCache. Enable it to see DC results.\n");
|
|
|
if (cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP) {
|
if (cpu_state.sprs[SPR_UPR] & SPR_UPR_IMP)
|
PRINTF("IMMU read: hit %d(%d%%), miss %d\n", immu_stats.fetch_tlbhit, (immu_stats.fetch_tlbhit * 100) / SD(immu_stats.fetch_tlbhit + immu_stats.fetch_tlbmiss), immu_stats.fetch_tlbmiss);
|
{
|
} else
|
PRINTF ("IMMU read: hit %d(%d%%), miss %d\n", immu_stats.fetch_tlbhit,
|
|
(immu_stats.fetch_tlbhit * 100) / SD (immu_stats.fetch_tlbhit +
|
|
immu_stats.fetch_tlbmiss),
|
|
immu_stats.fetch_tlbmiss);
|
|
}
|
|
else
|
PRINTF("No IMMU. Set UPR[IMP]\n");
|
PRINTF("No IMMU. Set UPR[IMP]\n");
|
|
|
if (cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP) {
|
if (cpu_state.sprs[SPR_UPR] & SPR_UPR_DMP)
|
PRINTF("DMMU read: hit %d(%d%%), miss %d\n", dmmu_stats.loads_tlbhit, (dmmu_stats.loads_tlbhit * 100) / SD(dmmu_stats.loads_tlbhit + dmmu_stats.loads_tlbmiss), dmmu_stats.loads_tlbmiss);
|
{
|
} else
|
PRINTF ("DMMU read: hit %d(%d%%), miss %d\n", dmmu_stats.loads_tlbhit,
|
|
(dmmu_stats.loads_tlbhit * 100) / SD (dmmu_stats.loads_tlbhit +
|
|
dmmu_stats.loads_tlbmiss),
|
|
dmmu_stats.loads_tlbmiss);
|
|
}
|
|
else
|
PRINTF("No DMMU. Set UPR[DMP]\n");
|
PRINTF("No DMMU. Set UPR[DMP]\n");
|
|
|
PRINTF("Additional LOAD CYCLES: %u STORE CYCLES: %u\n", runtime.sim.loadcycles, runtime.sim.storecycles);
|
PRINTF ("Additional LOAD CYCLES: %u STORE CYCLES: %u\n",
|
|
runtime.sim.loadcycles, runtime.sim.storecycles);
|
}
|
}
|
|
|
void printstats(int which)
|
void
|
|
printstats (int which)
|
{
|
{
|
int i, all = 0, dependall = 0;
|
int i, all = 0, dependall = 0;
|
|
|
if (which > 1 && which <= 5 && !config.cpu.dependstats) {
|
if (which > 1 && which <= 5 && !config.cpu.dependstats)
|
PRINTF("Hazard analysis disabled. Enable it to see analysis results.\n");
|
{
|
|
PRINTF
|
|
("Hazard analysis disabled. Enable it to see analysis results.\n");
|
return;
|
return;
|
}
|
}
|
|
|
switch (which) {
|
switch (which)
|
|
{
|
case 1:
|
case 1:
|
PRINTF("stats 1: Misc stats\n");
|
PRINTF("stats 1: Misc stats\n");
|
printotherstats(which);
|
printotherstats(which);
|
break;
|
break;
|
case 2:
|
case 2:
|
Line 219... |
Line 339... |
for(i = 0; i < SSTATS_LEN; i++)
|
for(i = 0; i < SSTATS_LEN; i++)
|
all += sstats[i].cnt_dynamic;
|
all += sstats[i].cnt_dynamic;
|
|
|
for(i = 0; i < SSTATS_LEN; i++)
|
for(i = 0; i < SSTATS_LEN; i++)
|
if (sstats[i].cnt_dynamic)
|
if (sstats[i].cnt_dynamic)
|
PRINTF(" %-15s used %6dx (%5.1f%%)\n", insn_name(sstats[i].insn), sstats[i].cnt_dynamic, (sstats[i].cnt_dynamic * 100.)/SD(all));
|
PRINTF (" %-15s used %6dx (%5.1f%%)\n", insn_name (sstats[i].insn),
|
|
sstats[i].cnt_dynamic,
|
|
(sstats[i].cnt_dynamic * 100.) / SD (all));
|
|
|
PRINTF("%d instructions (dynamic, single stats)\n", all);
|
PRINTF("%d instructions (dynamic, single stats)\n", all);
|
break;
|
break;
|
|
|
case 3:
|
case 3:
|
PRINTF ("stats 3: Instruction dependencies\n");
|
PRINTF ("stats 3: Instruction dependencies\n");
|
for(i = 0; i < DSTATS_LEN; i++) {
|
for (i = 0; i < DSTATS_LEN; i++)
|
|
{
|
all += dstats[i].cnt_dynamic;
|
all += dstats[i].cnt_dynamic;
|
dependall += dstats[i].depend;
|
dependall += dstats[i].depend;
|
}
|
}
|
|
|
for(i = 0; i < DSTATS_LEN; i++)
|
for(i = 0; i < DSTATS_LEN; i++)
|
if (dstats[i].cnt_dynamic) {
|
if (dstats[i].cnt_dynamic)
|
|
{
|
char temp[100];
|
char temp[100];
|
sprintf(temp, "%s, %s ", insn_name(dstats[i].insn1), insn_name(dstats[i].insn2));
|
sprintf (temp, "%s, %s ", insn_name (dstats[i].insn1),
|
PRINTF(" %-30s %6dx (%5.1f%%)", temp, dstats[i].cnt_dynamic, (dstats[i].cnt_dynamic * 100.)/SD(all));
|
insn_name (dstats[i].insn2));
|
PRINTF(" depend: %5.1f%%\n", (dstats[i].depend * 100.) / dstats[i].cnt_dynamic);
|
PRINTF (" %-30s %6dx (%5.1f%%)", temp, dstats[i].cnt_dynamic,
|
|
(dstats[i].cnt_dynamic * 100.) / SD (all));
|
|
PRINTF (" depend: %5.1f%%\n",
|
|
(dstats[i].depend * 100.) / dstats[i].cnt_dynamic);
|
}
|
}
|
|
|
PRINTF("%d instructions (dynamic, dependency stats) depend: %d%%\n", all, (dependall * 100) / SD(all));
|
PRINTF ("%d instructions (dynamic, dependency stats) depend: %d%%\n",
|
|
all, (dependall * 100) / SD (all));
|
break;
|
break;
|
|
|
case 4:
|
case 4:
|
PRINTF("stats 4: Functional units dependencies\n");
|
PRINTF("stats 4: Functional units dependencies\n");
|
for(i = 0; i < FSTATS_LEN; i++) {
|
for (i = 0; i < FSTATS_LEN; i++)
|
|
{
|
all += fstats[i].cnt_dynamic;
|
all += fstats[i].cnt_dynamic;
|
dependall += fstats[i].depend;
|
dependall += fstats[i].depend;
|
}
|
}
|
|
|
for(i = 0; i < FSTATS_LEN; i++)
|
for(i = 0; i < FSTATS_LEN; i++)
|
if (fstats[i].cnt_dynamic) {
|
if (fstats[i].cnt_dynamic)
|
|
{
|
char temp[100];
|
char temp[100];
|
sprintf(temp, "%s, %s", func_unit_str[fstats[i].insn1], func_unit_str[fstats[i].insn2]);
|
sprintf (temp, "%s, %s", func_unit_str[fstats[i].insn1],
|
PRINTF(" %-30s %6dx (%5.1f%%)", temp, fstats[i].cnt_dynamic, (fstats[i].cnt_dynamic * 100.)/SD(all));
|
func_unit_str[fstats[i].insn2]);
|
PRINTF(" depend: %5.1f%%\n", (fstats[i].depend * 100.) / fstats[i].cnt_dynamic);
|
PRINTF (" %-30s %6dx (%5.1f%%)", temp, fstats[i].cnt_dynamic,
|
}
|
(fstats[i].cnt_dynamic * 100.) / SD (all));
|
PRINTF ("%d instructions (dynamic, functional units stats) depend: %d%%\n\n", all, (dependall * 100) / SD(all));
|
PRINTF (" depend: %5.1f%%\n",
|
|
(fstats[i].depend * 100.) / fstats[i].cnt_dynamic);
|
|
}
|
|
PRINTF
|
|
("%d instructions (dynamic, functional units stats) depend: %d%%\n\n",
|
|
all, (dependall * 100) / SD (all));
|
break;
|
break;
|
|
|
case 5:
|
case 5:
|
PRINTF("stats 5: Raw register usage over time\n");
|
PRINTF("stats 5: Raw register usage over time\n");
|
#if RAW_RANGE_STATS
|
#if RAW_RANGE_STATS
|
for(i = 0; (i < MAX_RANGE); i++)
|
for(i = 0; (i < MAX_RANGE); i++)
|
PRINTF(" Register set and reused in %d. cycle: %d cases\n", i, raw_stats.range[i]);
|
PRINTF (" Register set and reused in %d. cycle: %d cases\n", i,
|
|
raw_stats.range[i]);
|
#endif
|
#endif
|
break;
|
break;
|
case 6:
|
case 6:
|
if (config.cpu.sbuf_len) {
|
if (config.cpu.sbuf_len)
|
|
{
|
extern int sbuf_total_cyc, sbuf_wait_cyc;
|
extern int sbuf_total_cyc, sbuf_wait_cyc;
|
PRINTF ("stats 6: Store buffer analysis\n");
|
PRINTF ("stats 6: Store buffer analysis\n");
|
PRINTF ("Using store buffer of length %i.\n", config.cpu.sbuf_len);
|
PRINTF ("Using store buffer of length %i.\n", config.cpu.sbuf_len);
|
PRINTF ("Number of total memory store cycles: %i/%lli\n", sbuf_total_cyc,
|
PRINTF ("Number of total memory store cycles: %i/%lli\n",
|
|
sbuf_total_cyc,
|
runtime.sim.cycles + sbuf_total_cyc - sbuf_wait_cyc);
|
runtime.sim.cycles + sbuf_total_cyc - sbuf_wait_cyc);
|
PRINTF ("Number of cycles waiting for memory stores: %i\n", sbuf_wait_cyc);
|
PRINTF ("Number of cycles waiting for memory stores: %i\n",
|
PRINTF ("Number of memory cycles spared: %i\n", sbuf_total_cyc - sbuf_wait_cyc);
|
sbuf_wait_cyc);
|
PRINTF ("Store speedup %3.2f%%, total speedup %3.2f%%\n", 100.*(sbuf_total_cyc - sbuf_wait_cyc)/sbuf_total_cyc,
|
PRINTF ("Number of memory cycles spared: %i\n",
|
100.*(sbuf_total_cyc - sbuf_wait_cyc) / (runtime.sim.cycles + sbuf_total_cyc - sbuf_wait_cyc));
|
sbuf_total_cyc - sbuf_wait_cyc);
|
} else
|
PRINTF ("Store speedup %3.2f%%, total speedup %3.2f%%\n",
|
PRINTF ("Store buffer analysis disabled. Enable it to see analysis results.\n");
|
100. * (sbuf_total_cyc - sbuf_wait_cyc) / sbuf_total_cyc,
|
|
100. * (sbuf_total_cyc -
|
|
sbuf_wait_cyc) / (runtime.sim.cycles +
|
|
sbuf_total_cyc - sbuf_wait_cyc));
|
|
}
|
|
else
|
|
PRINTF
|
|
("Store buffer analysis disabled. Enable it to see analysis results.\n");
|
break;
|
break;
|
default:
|
default:
|
PRINTF ("Please specify a stats group (1-6).\n");
|
PRINTF ("Please specify a stats group (1-6).\n");
|
break;
|
break;
|
}
|
}
|
#if 0
|
|
PRINTF("Byte ADD: %d instructions\n", or1k_mstats.byteadd);
|
|
#endif
|
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|