/* mprofiler.c -- memory profiling utility
|
/* mprofiler.c -- memory profiling utility
|
Copyright (C) 2002 Marko Mlinar, markom@opencores.org
|
Copyright (C) 2002 Marko Mlinar, markom@opencores.org
|
|
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
|
|
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
(at your option) any later version.
|
(at your option) any later version.
|
|
|
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU General Public License for more details.
|
GNU General Public License for more details.
|
|
|
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
/* Command line utility, that displays profiling information, generated
|
/* Command line utility, that displays profiling information, generated
|
by or1ksim. (use --mprofile option at command line, when running or1ksim. */
|
by or1ksim. (use --mprofile option at command line, when running or1ksim. */
|
|
|
#if HAVE_CONFIG_H
|
#if HAVE_CONFIG_H
|
#include <config.h>
|
#include <config.h>
|
#endif
|
#endif
|
|
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <string.h>
|
#include <string.h>
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#if HAVE_MALLOC_H
|
#if HAVE_MALLOC_H
|
#include <malloc.h> /* calloc, free */
|
#include <malloc.h> /* calloc, free */
|
#endif
|
#endif
|
#ifdef HAVE_INTTYPES_H
|
#ifdef HAVE_INTTYPES_H
|
#include <inttypes.h>
|
#include <inttypes.h>
|
#endif
|
#endif
|
|
|
#include "port.h"
|
#include "port.h"
|
#include "arch.h"
|
#include "arch.h"
|
#include "support/profile.h"
|
#include "support/profile.h"
|
#include "mprofiler.h"
|
#include "mprofiler.h"
|
#include "sim-config.h"
|
#include "sim-config.h"
|
|
|
struct memory_hash {
|
struct memory_hash {
|
struct memory_hash *next;
|
struct memory_hash *next;
|
oraddr_t addr;
|
oraddr_t addr;
|
unsigned long cnt[3]; /* Various counters */
|
unsigned long cnt[3]; /* Various counters */
|
} *hash[HASH_SIZE];
|
} *hash[HASH_SIZE];
|
|
|
/* Groups size -- how much addresses should be joined together */
|
/* Groups size -- how much addresses should be joined together */
|
int group_bits = 2;
|
int group_bits = 2;
|
|
|
/* Start address */
|
/* Start address */
|
oraddr_t start_addr = 0;
|
oraddr_t start_addr = 0;
|
|
|
/* End address */
|
/* End address */
|
oraddr_t end_addr = 0xffffffff;
|
oraddr_t end_addr = 0xffffffff;
|
|
|
/* File to read from */
|
/* File to read from */
|
static FILE *fprof = 0;
|
static FILE *fprof = 0;
|
|
|
void mp_help ()
|
void mp_help (void)
|
{
|
{
|
PRINTF ("mprofiler <-d|-p|-a|-w> [-f filename] [-g group] from to\n");
|
PRINTF ("mprofiler <-d|-p|-a|-w> [-f filename] [-g group] from to\n");
|
PRINTF ("\t-d\t--detail\t\tdetailed output\n");
|
PRINTF ("\t-d\t--detail\t\tdetailed output\n");
|
PRINTF ("\t-p\t--pretty\t\tpretty output\n");
|
PRINTF ("\t-p\t--pretty\t\tpretty output\n");
|
PRINTF ("\t-a\t--access\t\toutput accesses only\n");
|
PRINTF ("\t-a\t--access\t\toutput accesses only\n");
|
PRINTF ("\t-w\t--width\t\t\toutput by width\n");
|
PRINTF ("\t-w\t--width\t\t\toutput by width\n");
|
PRINTF ("\t-f\t--filename filename\tspecify mprofile file [sim.mprofile]\n");
|
PRINTF ("\t-f\t--filename filename\tspecify mprofile file [sim.mprofile]\n");
|
PRINTF ("\t-g\t--group bits\t\tgroup 2^bits successive\n");
|
PRINTF ("\t-g\t--group bits\t\tgroup 2^bits successive\n");
|
PRINTF ("\t\t\t\t\taddresses together [2]\n");
|
PRINTF ("\t\t\t\t\taddresses together [2]\n");
|
PRINTF ("\t-h\t--help\t\t\toutput this screen\n");
|
PRINTF ("\t-h\t--help\t\t\toutput this screen\n");
|
}
|
}
|
|
|
void hash_add (oraddr_t addr, int index)
|
void hash_add (oraddr_t addr, int index)
|
{
|
{
|
struct memory_hash *h = hash[HASH_FUNC(addr)];
|
struct memory_hash *h = hash[HASH_FUNC(addr)];
|
while (h && h->addr != addr) h = h->next;
|
while (h && h->addr != addr) h = h->next;
|
|
|
if (!h) {
|
if (!h) {
|
h = (struct memory_hash *)malloc (sizeof (struct memory_hash));
|
h = (struct memory_hash *)malloc (sizeof (struct memory_hash));
|
h->next = hash[HASH_FUNC(addr)];
|
h->next = hash[HASH_FUNC(addr)];
|
hash[HASH_FUNC(addr)] = h;
|
hash[HASH_FUNC(addr)] = h;
|
h->addr = addr;
|
h->addr = addr;
|
h->cnt[0] = h->cnt[1] = h->cnt[2] = 0;
|
h->cnt[0] = h->cnt[1] = h->cnt[2] = 0;
|
}
|
}
|
h->cnt[index]++;
|
h->cnt[index]++;
|
}
|
}
|
|
|
unsigned long hash_get (oraddr_t addr, int index)
|
unsigned long hash_get (oraddr_t addr, int index)
|
{
|
{
|
struct memory_hash *h = hash[HASH_FUNC(addr)];
|
struct memory_hash *h = hash[HASH_FUNC(addr)];
|
while (h && h->addr != addr) h = h->next;
|
while (h && h->addr != addr) h = h->next;
|
|
|
if (!h) return 0;
|
if (!h) return 0;
|
return h->cnt[index];
|
return h->cnt[index];
|
}
|
}
|
|
|
void init ()
|
void init (void)
|
{
|
{
|
int i;
|
int i;
|
for (i = 0; i < HASH_SIZE; i++)
|
for (i = 0; i < HASH_SIZE; i++)
|
hash[i] = NULL;
|
hash[i] = NULL;
|
}
|
}
|
|
|
void read_file (FILE *f, int mode)
|
void read_file (FILE *f, int mode)
|
{
|
{
|
struct mprofentry_struct buf[BUF_SIZE];
|
struct mprofentry_struct buf[BUF_SIZE];
|
int num_read;
|
int num_read;
|
do {
|
do {
|
int i;
|
int i;
|
num_read = fread (buf, sizeof (struct mprofentry_struct), BUF_SIZE, f);
|
num_read = fread (buf, sizeof (struct mprofentry_struct), BUF_SIZE, f);
|
for (i = 0; i < num_read; i++) if (buf[i].addr >= start_addr && buf[i].addr <= end_addr) {
|
for (i = 0; i < num_read; i++) if (buf[i].addr >= start_addr && buf[i].addr <= end_addr) {
|
int index;
|
int index;
|
unsigned t = buf[i].type;
|
unsigned t = buf[i].type;
|
if (t > 64) {
|
if (t > 64) {
|
PRINTF ("!");
|
PRINTF ("!");
|
t = 0;
|
t = 0;
|
}
|
}
|
if (mode == MODE_WIDTH) t >>= 3;
|
if (mode == MODE_WIDTH) t >>= 3;
|
else t &= 0x7;
|
else t &= 0x7;
|
|
|
switch (t) {
|
switch (t) {
|
case 1: index = 0; break;
|
case 1: index = 0; break;
|
case 2: index = 1; break;
|
case 2: index = 1; break;
|
case 4: index = 2; break;
|
case 4: index = 2; break;
|
default:
|
default:
|
index = 0;
|
index = 0;
|
PRINTF ("!!!!");
|
PRINTF ("!!!!");
|
break;
|
break;
|
}
|
}
|
hash_add (buf[i].addr >> group_bits, index);
|
hash_add (buf[i].addr >> group_bits, index);
|
}
|
}
|
} while (num_read > 0);
|
} while (num_read > 0);
|
}
|
}
|
|
|
static inline int nbits (unsigned long a)
|
static inline int nbits (unsigned long a)
|
{
|
{
|
int cnt = 0;
|
int cnt = 0;
|
int b = a;
|
int b = a;
|
if (!a) return 0;
|
if (!a) return 0;
|
|
|
while (a) a >>= 1, cnt++;
|
while (a) a >>= 1, cnt++;
|
if (cnt > 1 && ((b >> (cnt - 2)) & 1))
|
if (cnt > 1 && ((b >> (cnt - 2)) & 1))
|
cnt = cnt * 2 + 1;
|
cnt = cnt * 2 + 1;
|
else
|
else
|
cnt *= 2;
|
cnt *= 2;
|
|
|
return cnt - 1;
|
return cnt - 1;
|
}
|
}
|
|
|
void printout (int mode)
|
void printout (int mode)
|
{
|
{
|
oraddr_t addr = start_addr & ~((1 << group_bits) - 1);
|
oraddr_t addr = start_addr & ~((1 << group_bits) - 1);
|
PRINTF ("start = %"PRIxADDR" (%"PRIxADDR"); end = %"PRIxADDR"; group_bits = %08x\n", start_addr, addr, end_addr, (1 << group_bits) - 1);
|
PRINTF ("start = %"PRIxADDR" (%"PRIxADDR"); end = %"PRIxADDR"; group_bits = %08x\n", start_addr, addr, end_addr, (1 << group_bits) - 1);
|
for (; addr <= end_addr; addr += (1 << group_bits)) {
|
for (; addr <= end_addr; addr += (1 << group_bits)) {
|
int i;
|
int i;
|
unsigned long a = hash_get (addr >> group_bits, 0);
|
unsigned long a = hash_get (addr >> group_bits, 0);
|
unsigned long b = hash_get (addr >> group_bits, 1);
|
unsigned long b = hash_get (addr >> group_bits, 1);
|
unsigned long c = hash_get (addr >> group_bits, 2);
|
unsigned long c = hash_get (addr >> group_bits, 2);
|
PRINTF ("%"PRIxADDR":", addr);
|
PRINTF ("%"PRIxADDR":", addr);
|
switch (mode) {
|
switch (mode) {
|
case MODE_DETAIL:
|
case MODE_DETAIL:
|
if (a) PRINTF (" %10li R", a);
|
if (a) PRINTF (" %10li R", a);
|
else PRINTF (" R");
|
else PRINTF (" R");
|
if (b) PRINTF (" %10li W", b);
|
if (b) PRINTF (" %10li W", b);
|
else PRINTF (" W");
|
else PRINTF (" W");
|
if (c) PRINTF (" %10li F", c);
|
if (c) PRINTF (" %10li F", c);
|
else PRINTF (" F");
|
else PRINTF (" F");
|
break;
|
break;
|
case MODE_ACCESS:
|
case MODE_ACCESS:
|
PRINTF (" %10li", a + b + c);
|
PRINTF (" %10li", a + b + c);
|
break;
|
break;
|
case MODE_PRETTY:
|
case MODE_PRETTY:
|
PRINTF (" %10li ", a + b + c);
|
PRINTF (" %10li ", a + b + c);
|
for (i = 0; i < nbits (a + b + c); i++)
|
for (i = 0; i < nbits (a + b + c); i++)
|
PRINTF ("#");
|
PRINTF ("#");
|
#if 0
|
#if 0
|
for (; i < 64; i++)
|
for (; i < 64; i++)
|
PRINTF (".");
|
PRINTF (".");
|
#endif
|
#endif
|
break;
|
break;
|
case MODE_WIDTH:
|
case MODE_WIDTH:
|
if (a) PRINTF (" %10li B", a);
|
if (a) PRINTF (" %10li B", a);
|
else PRINTF (" B");
|
else PRINTF (" B");
|
if (b) PRINTF (" %10li H", b);
|
if (b) PRINTF (" %10li H", b);
|
else PRINTF (" H");
|
else PRINTF (" H");
|
if (c) PRINTF (" %10li W", c);
|
if (c) PRINTF (" %10li W", c);
|
else PRINTF (" W");
|
else PRINTF (" W");
|
break;
|
break;
|
}
|
}
|
PRINTF ("\n");
|
PRINTF ("\n");
|
if (addr >= addr + (1 << group_bits)) break; /* Overflow? */
|
if (addr >= addr + (1 << group_bits)) break; /* Overflow? */
|
}
|
}
|
}
|
}
|
|
|
int main_mprofiler (int argc, char *argv[])
|
int main_mprofiler (int argc, char *argv[])
|
{
|
{
|
char fmprofname[50] = "sim.mprofile";
|
char fmprofname[50] = "sim.mprofile";
|
int param = 0;
|
int param = 0;
|
int mode = MODE_DETAIL;
|
int mode = MODE_DETAIL;
|
|
|
argv++; argc--;
|
argv++; argc--;
|
while (argc > 0) {
|
while (argc > 0) {
|
if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "--detail")) {
|
if (!strcmp(argv[0], "-d") || !strcmp(argv[0], "--detail")) {
|
mode = MODE_DETAIL;
|
mode = MODE_DETAIL;
|
argv++; argc--;
|
argv++; argc--;
|
} else if (!strcmp(argv[0], "-p") || !strcmp(argv[0], "--pretty")) {
|
} else if (!strcmp(argv[0], "-p") || !strcmp(argv[0], "--pretty")) {
|
mode = MODE_PRETTY;
|
mode = MODE_PRETTY;
|
argv++; argc--;
|
argv++; argc--;
|
} else if (!strcmp(argv[0], "-a") || !strcmp(argv[0], "--access")) {
|
} else if (!strcmp(argv[0], "-a") || !strcmp(argv[0], "--access")) {
|
mode = MODE_ACCESS;
|
mode = MODE_ACCESS;
|
argv++; argc--;
|
argv++; argc--;
|
} else if (!strcmp(argv[0], "-w") || !strcmp(argv[0], "--width")) {
|
} else if (!strcmp(argv[0], "-w") || !strcmp(argv[0], "--width")) {
|
mode = MODE_WIDTH;
|
mode = MODE_WIDTH;
|
argv++; argc--;
|
argv++; argc--;
|
} else if (!strcmp(argv[0], "-g") || !strcmp(argv[0], "--group")) {
|
} else if (!strcmp(argv[0], "-g") || !strcmp(argv[0], "--group")) {
|
argv++; argc--;
|
argv++; argc--;
|
group_bits = strtoul (argv[0], NULL, 0);
|
group_bits = strtoul (argv[0], NULL, 0);
|
argv++; argc--;
|
argv++; argc--;
|
} else if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help")) {
|
} else if (!strcmp(argv[0], "-h") || !strcmp(argv[0], "--help")) {
|
mp_help ();
|
mp_help ();
|
return 0;
|
return 0;
|
} else if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--filename")) {
|
} else if (!strcmp(argv[0], "-f") || !strcmp(argv[0], "--filename")) {
|
argv++; argc--;
|
argv++; argc--;
|
strcpy (&fmprofname[0], argv[0]);
|
strcpy (&fmprofname[0], argv[0]);
|
argv++; argc--;
|
argv++; argc--;
|
} else {
|
} else {
|
switch (param) {
|
switch (param) {
|
case 0:
|
case 0:
|
start_addr = strtoul (argv[0], NULL, 0);
|
start_addr = strtoul (argv[0], NULL, 0);
|
break;
|
break;
|
case 1:
|
case 1:
|
end_addr = strtoul (argv[0], NULL, 0);
|
end_addr = strtoul (argv[0], NULL, 0);
|
break;
|
break;
|
default:
|
default:
|
fprintf (stderr, "Invalid number of parameters.\n");
|
fprintf (stderr, "Invalid number of parameters.\n");
|
return -1;
|
return -1;
|
}
|
}
|
argv++; argc--; param++;
|
argv++; argc--; param++;
|
}
|
}
|
}
|
}
|
|
|
fprof = fopen (fmprofname, "rm");
|
fprof = fopen (fmprofname, "rm");
|
|
|
if (!fprof) {
|
if (!fprof) {
|
fprintf (stderr, "Cannot open profile file: %s\n", fmprofname);
|
fprintf (stderr, "Cannot open profile file: %s\n", fmprofname);
|
return 1;
|
return 1;
|
}
|
}
|
|
|
init ();
|
init ();
|
read_file (fprof, mode);
|
read_file (fprof, mode);
|
fclose (fprof);
|
fclose (fprof);
|
printout (mode);
|
printout (mode);
|
return 0;
|
return 0;
|
}
|
}
|
|
|