/* 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
|
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
|
Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
|
Copyright (C) 2008 Embecosm Limited
|
Copyright (C) 2008 Embecosm Limited
|
|
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
|
|
|
This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
|
This file is part of Or1ksim, the OpenRISC 1000 Architectural Simulator.
|
|
|
This program is free software; you can redistribute it and/or modify it
|
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
|
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)
|
Software Foundation; either version 3 of the License, or (at your option)
|
any later version.
|
any later version.
|
|
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
more details.
|
more details.
|
|
|
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License along
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
/* This program is commented throughout in a fashion suitable for processing
|
/* This program is commented throughout in a fashion suitable for processing
|
with Doxygen. */
|
with Doxygen. */
|
|
|
|
|
/* Autoconf and/or portability configuration */
|
/* Autoconf and/or portability configuration */
|
#include "config.h"
|
#include "config.h"
|
#include "port.h"
|
#include "port.h"
|
|
|
/* System includes */
|
/* System includes */
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <regex.h>
|
#include <regex.h>
|
|
|
/* Package includes */
|
/* Package includes */
|
#include "mprofiler.h"
|
#include "mprofiler.h"
|
#include "sim-config.h"
|
#include "sim-config.h"
|
#include "argtable2.h"
|
#include "argtable2.h"
|
#include "support/profile.h"
|
#include "support/profile.h"
|
|
|
/* output modes */
|
/* output modes */
|
#define MODE_DETAIL 0
|
#define MODE_DETAIL 0
|
#define MODE_PRETTY 1
|
#define MODE_PRETTY 1
|
#define MODE_ACCESS 2
|
#define MODE_ACCESS 2
|
#define MODE_WIDTH 3
|
#define MODE_WIDTH 3
|
|
|
/* Input buffer size */
|
/* Input buffer size */
|
#define BUF_SIZE 256
|
#define BUF_SIZE 256
|
|
|
/* HASH */
|
/* HASH */
|
#define HASH_SIZE 0x10000
|
#define HASH_SIZE 0x10000
|
#define HASH_FUNC(x) ((x) & 0xffff)
|
#define HASH_FUNC(x) ((x) & 0xffff)
|
|
|
/*! Hash table data structure */
|
/*! Hash table data structure */
|
static struct memory_hash
|
static 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 */
|
static int group_bits = 2;
|
static int group_bits = 2;
|
|
|
/*! Start address */
|
/*! Start address */
|
static oraddr_t start_addr = 0;
|
static oraddr_t start_addr = 0;
|
|
|
/*! End address */
|
/*! End address */
|
static oraddr_t end_addr = 0xffffffff;
|
static oraddr_t end_addr = 0xffffffff;
|
|
|
/* File to read from */
|
/* File to read from */
|
static FILE *fprof = 0;
|
static FILE *fprof = 0;
|
|
|
static void
|
static void
|
hash_add (oraddr_t addr, int index)
|
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)
|
while (h && h->addr != addr)
|
h = h->next;
|
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]++;
|
}
|
}
|
|
|
|
|
static unsigned long
|
static unsigned long
|
hash_get (oraddr_t addr, int index)
|
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)
|
while (h && h->addr != addr)
|
h = h->next;
|
h = h->next;
|
|
|
if (!h)
|
if (!h)
|
return 0;
|
return 0;
|
return h->cnt[index];
|
return h->cnt[index];
|
}
|
}
|
|
|
static void
|
static void
|
init ()
|
init ()
|
{
|
{
|
int i;
|
int i;
|
for (i = 0; i < HASH_SIZE; i++)
|
for (i = 0; i < HASH_SIZE; i++)
|
hash[i] = NULL;
|
hash[i] = NULL;
|
}
|
}
|
|
|
static void
|
static void
|
read_file (FILE * f, int mode)
|
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++)
|
for (i = 0; i < num_read; i++)
|
if (buf[i].addr >= start_addr && buf[i].addr <= end_addr)
|
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)
|
if (mode == MODE_WIDTH)
|
t >>= 3;
|
t >>= 3;
|
else
|
else
|
t &= 0x7;
|
t &= 0x7;
|
|
|
switch (t)
|
switch (t)
|
{
|
{
|
case 1:
|
case 1:
|
index = 0;
|
index = 0;
|
break;
|
break;
|
case 2:
|
case 2:
|
index = 1;
|
index = 1;
|
break;
|
break;
|
case 4:
|
case 4:
|
index = 2;
|
index = 2;
|
break;
|
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 int
|
static int
|
nbits (unsigned long a)
|
nbits (unsigned long a)
|
{
|
{
|
int cnt = 0;
|
int cnt = 0;
|
int b = a;
|
int b = a;
|
if (!a)
|
if (!a)
|
return 0;
|
return 0;
|
|
|
while (a)
|
while (a)
|
a >>= 1, cnt++;
|
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;
|
}
|
}
|
|
|
static void
|
static void
|
printout (int mode)
|
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
|
PRINTF ("start = %" PRIxADDR " (%" PRIxADDR "); end = %" PRIxADDR
|
"; group_bits = %08x\n", start_addr, addr, end_addr,
|
"; group_bits = %08x\n", start_addr, addr, end_addr,
|
(1 << group_bits) - 1);
|
(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)
|
if (a)
|
PRINTF (" %10li R", a);
|
PRINTF (" %10li R", a);
|
else
|
else
|
PRINTF (" R");
|
PRINTF (" R");
|
if (b)
|
if (b)
|
PRINTF (" %10li W", b);
|
PRINTF (" %10li W", b);
|
else
|
else
|
PRINTF (" W");
|
PRINTF (" W");
|
if (c)
|
if (c)
|
PRINTF (" %10li F", c);
|
PRINTF (" %10li F", c);
|
else
|
else
|
PRINTF (" F");
|
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 ("#");
|
break;
|
break;
|
case MODE_WIDTH:
|
case MODE_WIDTH:
|
if (a)
|
if (a)
|
PRINTF (" %10li B", a);
|
PRINTF (" %10li B", a);
|
else
|
else
|
PRINTF (" B");
|
PRINTF (" B");
|
if (b)
|
if (b)
|
PRINTF (" %10li H", b);
|
PRINTF (" %10li H", b);
|
else
|
else
|
PRINTF (" H");
|
PRINTF (" H");
|
if (c)
|
if (c)
|
PRINTF (" %10li W", c);
|
PRINTF (" %10li W", c);
|
else
|
else
|
PRINTF (" W");
|
PRINTF (" W");
|
break;
|
break;
|
}
|
}
|
PRINTF ("\n");
|
PRINTF ("\n");
|
if (addr >= addr + (1 << group_bits))
|
if (addr >= addr + (1 << group_bits))
|
break; /* Overflow? */
|
break; /* Overflow? */
|
}
|
}
|
}
|
}
|
|
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
/*! Parse the arguments for the profiling utility
|
/*! Parse the arguments for the profiling utility
|
|
|
Updated by Jeremy Bennett to use argtable2. Also has an option just to
|
Updated by Jeremy Bennett to use argtable2. Also has an option just to
|
print help, for use with the CLI.
|
print help, for use with the CLI.
|
|
|
@param[in] argc Number of command args
|
@param[in] argc Number of command args
|
@param[in] argv Vector of the command args
|
@param[in] argv Vector of the command args
|
@param[in] just_help If 1 (true), ignore argc & argv and just print out
|
@param[in] just_help If 1 (true), ignore argc & argv and just print out
|
the help message without parsing args
|
the help message without parsing args
|
|
|
@return 0 on success, 1 on failure */
|
@return 0 on success, 1 on failure */
|
/*---------------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------------*/
|
int
|
int
|
main_mprofiler (int argc, char *argv[], int just_help)
|
main_mprofiler (int argc, char *argv[], int just_help)
|
{
|
{
|
struct arg_lit *vercop;
|
struct arg_lit *vercop;
|
struct arg_lit *help;
|
struct arg_lit *help;
|
struct arg_rex *mode_arg;
|
struct arg_rex *mode_arg;
|
struct arg_int *group;
|
struct arg_int *group;
|
struct arg_file *prof_file;
|
struct arg_file *prof_file;
|
struct arg_int *from;
|
struct arg_int *from;
|
struct arg_int *to;
|
struct arg_int *to;
|
struct arg_end *end;
|
struct arg_end *end;
|
|
|
void *argtab[8];
|
void *argtab[8];
|
int nerrors;
|
int nerrors;
|
|
|
int mode = MODE_DETAIL;
|
int mode = MODE_DETAIL;
|
|
|
/* Specify each argument, with fallback values */
|
/* Specify each argument, with fallback values.
|
|
|
|
Bug 1710 (Vinay Patil) fixed. mode should allow REG_EXTENDED. */
|
vercop = arg_lit0 ("v", "version", "version and copyright notice");
|
vercop = arg_lit0 ("v", "version", "version and copyright notice");
|
help = arg_lit0 ("h", "help", "print this help message");
|
help = arg_lit0 ("h", "help", "print this help message");
|
mode_arg = arg_rex0 ("m", "mode",
|
mode_arg = arg_rex0 ("m", "mode",
|
"(detailed|d)|(pretty|p)|(access|a)|"
|
"(detailed|d)|(pretty|p)|(access|a)|"
|
"(width|w)", "<m>", REG_ICASE,
|
"(width|w)", "<m>", REG_ICASE | REG_EXTENDED,
|
"Output mode (detailed, pretty, access " "or width)");
|
"Output mode (detailed, pretty, access " "or width)");
|
mode_arg->sval[0] = "detailed";
|
mode_arg->sval[0] = "detailed";
|
group = arg_int0 ("g", "group", "<n>",
|
group = arg_int0 ("g", "group", "<n>",
|
"group 2^n bits successive addresses " "together");
|
"group 2^n bits successive addresses " "together");
|
group->ival[0] = 0;
|
group->ival[0] = 0;
|
prof_file = arg_file0 ("f", "filename", "<file>",
|
prof_file = arg_file0 ("f", "filename", "<file>",
|
"data file to analyse (default " "sim.mprofile)");
|
"data file to analyse (default " "sim.mprofile)");
|
prof_file->filename[0] = "sim.mprofile";
|
prof_file->filename[0] = "sim.mprofile";
|
from = arg_int1 (NULL, NULL, "<from>", "start address");
|
from = arg_int1 (NULL, NULL, "<from>", "start address");
|
to = arg_int1 (NULL, NULL, "<to>", "end address");
|
to = arg_int1 (NULL, NULL, "<to>", "end address");
|
end = arg_end (20);
|
end = arg_end (20);
|
|
|
/* Set up the argument table */
|
/* Set up the argument table */
|
argtab[0] = vercop;
|
argtab[0] = vercop;
|
argtab[1] = help;
|
argtab[1] = help;
|
argtab[2] = mode_arg;
|
argtab[2] = mode_arg;
|
argtab[3] = group;
|
argtab[3] = group;
|
argtab[4] = prof_file;
|
argtab[4] = prof_file;
|
argtab[5] = from;
|
argtab[5] = from;
|
argtab[6] = to;
|
argtab[6] = to;
|
argtab[7] = end;
|
argtab[7] = end;
|
|
|
/* If we are just asked for a help message, then we don't parse the
|
/* If we are just asked for a help message, then we don't parse the
|
args. This is used to implement the help function from the CLI. */
|
args. This is used to implement the help function from the CLI. */
|
if (just_help)
|
if (just_help)
|
{
|
{
|
printf ("mprofile");
|
printf ("mprofile");
|
arg_print_syntax (stdout, argtab, "\n");
|
arg_print_syntax (stdout, argtab, "\n");
|
arg_print_glossary (stdout, argtab, " %-25s %s\n");
|
arg_print_glossary (stdout, argtab, " %-25s %s\n");
|
|
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Parse */
|
/* Parse */
|
nerrors = arg_parse (argc, argv, argtab);
|
nerrors = arg_parse (argc, argv, argtab);
|
|
|
/* Special case here is if help or version is specified, we ignore any other
|
/* Special case here is if help or version is specified, we ignore any other
|
errors and just print the help or version information and then give up. */
|
errors and just print the help or version information and then give up. */
|
if (vercop->count > 0)
|
if (vercop->count > 0)
|
{
|
{
|
PRINTF ("OpenRISC 1000 Memory Profiling Utility, version %s\n",
|
PRINTF ("OpenRISC 1000 Memory Profiling Utility, version %s\n",
|
PACKAGE_VERSION);
|
PACKAGE_VERSION);
|
|
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
return 0;
|
return 0;
|
}
|
}
|
|
|
if (help->count > 0)
|
if (help->count > 0)
|
{
|
{
|
printf ("Usage: %s ", argv[0]);
|
printf ("Usage: %s ", argv[0]);
|
arg_print_syntax (stdout, argtab, "\n");
|
arg_print_syntax (stdout, argtab, "\n");
|
arg_print_glossary (stdout, argtab, " %-25s %s\n");
|
arg_print_glossary (stdout, argtab, " %-25s %s\n");
|
|
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
return 0;
|
return 0;
|
}
|
}
|
|
|
/* Deal with any errors */
|
/* Deal with any errors */
|
if (0 != nerrors)
|
if (0 != nerrors)
|
{
|
{
|
arg_print_errors (stderr, end, "mprofile");
|
arg_print_errors (stderr, end, "mprofile");
|
fprintf (stderr, "Usage: %s ", argv[0]);
|
fprintf (stderr, "Usage: %s ", argv[0]);
|
arg_print_syntaxv (stderr, argtab, "\n");
|
arg_print_syntaxv (stderr, argtab, "\n");
|
|
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/* If version or help is requested, that is all that is printed out */
|
/* If version or help is requested, that is all that is printed out
|
/* Sort out the mode */
|
Sort out the mode.
|
|
|
|
Bug 1710 fixed (Vinay Patil). Modes now set correctly (were all set to
|
|
detail). */
|
if ((0 == strcmp (mode_arg->sval[0], "detail")) ||
|
if ((0 == strcmp (mode_arg->sval[0], "detail")) ||
|
(0 == strcmp (mode_arg->sval[0], "d")))
|
(0 == strcmp (mode_arg->sval[0], "d")))
|
{
|
{
|
mode = MODE_DETAIL;
|
mode = MODE_DETAIL;
|
}
|
}
|
else if ((0 == strcmp (mode_arg->sval[0], "pretty")) ||
|
else if ((0 == strcmp (mode_arg->sval[0], "pretty")) ||
|
(0 == strcmp (mode_arg->sval[0], "p")))
|
(0 == strcmp (mode_arg->sval[0], "p")))
|
{
|
{
|
mode = MODE_DETAIL;
|
mode = MODE_PRETTY;
|
}
|
}
|
else if ((0 == strcmp (mode_arg->sval[0], "access")) ||
|
else if ((0 == strcmp (mode_arg->sval[0], "access")) ||
|
(0 == strcmp (mode_arg->sval[0], "a")))
|
(0 == strcmp (mode_arg->sval[0], "a")))
|
{
|
{
|
mode = MODE_DETAIL;
|
mode = MODE_ACCESS;
|
}
|
}
|
else if ((0 == strcmp (mode_arg->sval[0], "width")) ||
|
else if ((0 == strcmp (mode_arg->sval[0], "width")) ||
|
(0 == strcmp (mode_arg->sval[0], "w")))
|
(0 == strcmp (mode_arg->sval[0], "w")))
|
{
|
{
|
mode = MODE_DETAIL;
|
mode = MODE_WIDTH;
|
}
|
}
|
else
|
else
|
{
|
{
|
fprintf (stderr, "Impossible mode: %s\n", mode_arg->sval[0]);
|
fprintf (stderr, "Impossible mode: %s\n", mode_arg->sval[0]);
|
}
|
}
|
|
|
/* Group bits */
|
/* Group bits */
|
group_bits = group->ival[0];
|
group_bits = group->ival[0];
|
|
|
/* Start and end addresses */
|
/* Start and end addresses */
|
start_addr = from->ival[0];
|
start_addr = from->ival[0];
|
end_addr = to->ival[0];
|
end_addr = to->ival[0];
|
|
|
/* Get the profile */
|
/* Get the profile */
|
fprof = fopen (prof_file->filename[0], "rm");
|
fprof = fopen (prof_file->filename[0], "rm");
|
|
|
if (!fprof)
|
if (!fprof)
|
{
|
{
|
fprintf (stderr, "Cannot open profile file: %s\n",
|
fprintf (stderr, "Cannot open profile file: %s\n",
|
prof_file->filename[0]);
|
prof_file->filename[0]);
|
|
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
return 1;
|
return 1;
|
}
|
}
|
|
|
/* Finished with the args */
|
/* Finished with the args */
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
arg_freetable (argtab, sizeof (argtab) / sizeof (argtab[0]));
|
|
|
init ();
|
init ();
|
read_file (fprof, mode);
|
read_file (fprof, mode);
|
fclose (fprof);
|
fclose (fprof);
|
printout (mode);
|
printout (mode);
|
return 0;
|
return 0;
|
|
|
} /* main_mprofiler () */
|
} /* main_mprofiler () */
|
|
|