Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
kcc-5/lib/test/tmall1.c
There are 5 other files named tmall1.c in the archive. Click here to see a list.
#include <stdio.h>
#include <c-env.h>
#ifndef DBG
#define DBG 0
#endif
#if SYS_T20
#define extern
#define add_to_events addvnt
#define cause_core_dump cordmp
#define do_stats dostat
#define dump_events dmpvnt
#define free_event frevnt
#define init_events inivnt
#define random_range ranrng
#define realloc_event reavnt
#define realloc_probability reaprb
#define run_test runtst
#endif
extern int atoi ();
extern long random ();
extern char *sbrk ();
extern char *malloc ();
extern char *realloc ();
extern int free ();
struct memevent {
int m_time; /* time to go */
char *m_memory; /* malloc'ed mem */
unsigned m_size; /* size of mem */
int m_id; /* id, for trace/debug */
int m_realloc; /* counter, for debugging */
char m_pattern; /* pattern in memory */
struct memevent *m_next; /* linked list pointer */
};
#ifndef MAX_EVENTS
#define MAX_EVENTS 10000
#endif
struct memevent eventpool[ MAX_EVENTS ];
struct memevent *events;
struct memevent *free_events;
char stdout_buf[ BUFSIZ ];
char stderr_buf[ BUFSIZ ];
int time_to_go;
int new_probability;
int realloc_probability = 25; /* XXX: should set from argv */
int stat_frequency;
main (argc, argv)
int argc;
char *argv[];
{
init (argc, argv);
run_test ();
}
/*
* run_test ()
*
* Run the actual memory test.
*/
run_test ()
{
while (time_to_go > 0) {
arrival ();
service ();
-- time_to_go;
if ((time_to_go % stat_frequency) == 0)
do_stats ();
}
}
/*
* arrival ()
*
* With probability new_probability/100, allocate a new piece
* of memory with some randomly determined size and lifetime,
* and add it to the memory event list.
*/
arrival ()
{
if (free_events && odds (new_probability, 100)) {
register struct memevent *m;
register char *p;
m = free_events;
free_events = m->m_next;
m->m_next = NULL;
/* XXX: let these be set from argv */
m->m_size = (unsigned) random_range (1, 100);
if (time_to_go < 100)
m->m_time = random_range (1, time_to_go);
else
m->m_time = random_range (1, 100);
m->m_pattern = (char) random_range (0, 127);
m->m_realloc = 0;
m->m_memory = malloc (m->m_size);
if (! m->m_memory)
out_of_memory ();
for (p = m->m_memory; p < & m->m_memory[ m->m_size ]; p++)
*p = m->m_pattern;
add_to_events (m);
}
} /* arrival */
/*
* do_stats ()
*/
do_stats ()
{
register struct memevent *m;
int i;
long total;
printf ("---------------------\nTIME Remaining: %d\n", time_to_go);
/* print other interesting but implementation-dependent stuff here
(like count of blocks in heap, size of heap, etc) */
total = 0;
for (i = 1, m = events; m != NULL; m = m->m_next, i++) {
printf ("EVENT %5d (id %5d): ", i, m->m_id);
printf ("SIZE %4d, ", m->m_size);
printf ("PATTERN 0x%02x, ", m->m_pattern & 0xFF);
printf ("TIME %4d ", m->m_time);
if (m->m_realloc > 0)
printf ("REALLOC %d", m->m_realloc);
printf ("\n");
total += m->m_size;
}
printf ("TOTAL events %d, allocated memory %d\n", i-1, total);
(void) fflush (stdout);
} /* do_stats */
/*
* service ()
*
* Decrement the time remaining on the head event. If
* it's time is up (zero), service it.
*
* Servicing an event generally means free'ing it (after checking
* for corruption). It is also possible (realloc_probability) to
* realloc the event instead.
*/
service ()
{
register struct memevent *m;
if ((m = events) != NULL)
-- m->m_time;
while (m != NULL && m->m_time == 0) {
register char *p;
for (p = m->m_memory; p < & m->m_memory[ m->m_size ]; p++) {
if (*p != m->m_pattern)
corrupted ();
}
events = m->m_next; /* delete this event */
if (time_to_go > 1 && odds (realloc_probability, 100))
realloc_event (m);
else
free_event (m);
m = events;
}
} /* service */
/*
* free_event (m)
*
* Called to free up the given event, including its memory.
*/
free_event (m)
register struct memevent *m;
{
free ((char*)m->m_memory);
m->m_next = free_events;
free_events = m;
}
/*
* realloc_event (m)
*
* Called from service(), to reallocate an event's memory,
* rather than freeing it.
*/
realloc_event (m)
register struct memevent *m;
{
register char *p;
unsigned new_size;
unsigned min_size;
/* XXX: let these be set from argv */
new_size = (unsigned) random_range (1, 100);
++ m->m_realloc; /* for stats */
m->m_memory = realloc (m->m_memory, new_size);
if (! m->m_memory)
out_of_memory ();
m->m_next = NULL;
if (time_to_go < 100)
m->m_time = random_range (1, time_to_go - 1);
else
m->m_time = random_range (1, 100); /* XXX: should set from argv */
min_size = new_size > m->m_size ? m->m_size : new_size;
for (p = m->m_memory; p < & m->m_memory[ min_size ]; p++) {
if (*p != m->m_pattern)
corrupted ();
}
m->m_size = new_size;
for (p = m->m_memory; p < & m->m_memory[ m->m_size ]; p++)
*p = m->m_pattern;
add_to_events (m);
} /* realloc_event */
/*
* add_to_events (m)
*
* Add the given event structure onto the time-ordered event list.
*/
add_to_events (m)
register struct memevent *m;
{
register struct memevent *l;
register struct memevent *ol;
for (ol = NULL, l = events; l != NULL; ol = l, l = l->m_next) {
if (l->m_time > m->m_time) {
if (ol == NULL) {
m->m_next = events;
events = m;
}
else {
m->m_next = l;
ol->m_next = m;
}
l->m_time -= m->m_time;
return;
}
m->m_time -= l->m_time;
}
if (events == NULL)
events = m;
else
ol->m_next = m;
} /* add_to_events */
/*
* init_events ()
*
* Set up the memevent pools.
*/
init_events ()
{
register struct memevent *m;
int i;
for (i = 0, m = eventpool; m < & eventpool[ MAX_EVENTS ]; m++, i++) {
m->m_id = i;
m->m_next = m + 1;
}
eventpool[ MAX_EVENTS-1 ].m_next = NULL;
free_events = eventpool;
}
/*
* init (argc, argv)
*
* Initialize the memory tests.
*/
init (argc, argv)
int argc;
char *argv[];
{
if (argc != 4) {
fprintf (stderr, "usage: %s new_prob time_to_go stat_freq\n", argv[ 0 ]);
exit (1);
}
new_probability = atoi (argv[ 1 ]);
time_to_go = atoi (argv[ 2 ]);
stat_frequency = atoi (argv[ 3 ]);
srand (1);
init_events ();
/*
* Use statically allocated buffers, otherwise
* stdio() will call malloc to allocate buffers, and
* this gets confusing when debugging stuff.
*/
setbuf (stdout, stdout_buf);
setbuf (stderr, stderr_buf);
}
/*
* XXX: Should really send SIGQUIT ...
*/
cause_core_dump ()
{
* (long *) 1 = 5;
}
corrupted ()
{
printf ("Corrupted\n");
cause_core_dump ();
}
out_of_memory ()
{
printf ("Out of memory!\n");
cause_core_dump ();
}
/*
* odds (m, n)
*
* Return TRUE (non-zero) with probability m out of n.
*/
odds (m, n)
int m;
int n;
{
return ((rand () % n) < m);
}
/*
* random_range (lo, hi)
*
* Pick a random integer from lo to hi (inclusive).
*/
random_range (lo, hi)
int lo;
int hi;
{
return ((rand () % (hi - lo + 1)) + lo);
}
#if DBG
/*
* de_cmpf (m1,m2)
*
* compare function for qsort() in dump_events.
* Sort by memory address of the memory allocated to
* the event.
*/
int
de_cmpf (m1, m2)
struct memevent **m1;
struct memevent **m2;
{
unsigned long maddr1 = (unsigned long) (*m1)->m_memory;
unsigned long maddr2 = (unsigned long) (*m2)->m_memory;
/* sloppy */
return (maddr1 - maddr2);
}
#endif DBG
/*
* dump_events ()
*
* Useful for debugging.
*/
#if DBG
dump_events ()
{
static struct memevent *sorted[ MAX_EVENTS ];
register struct memevent *m;
register int i;
fprintf (stderr, "DUMP EVENTS (time remaining = %d)\n", time_to_go);
for (m = events, i = 0; m != NULL; m = m->m_next, i++)
sorted[ i ] = m;
if (i == 0) {
fprintf (stderr, "No events.\n");
return;
}
qsort ((char *) sorted, i, sizeof (struct memevent *), de_cmpf);
sorted[ i ] = 0;
for (i = 0, m = sorted[ 0 ]; m != NULL; m = sorted[ ++i ]) {
fprintf (stderr, "E# %3d: ", m->m_id);
fprintf (stderr, "SIZ%4d, ", m->m_size);
fprintf (stderr, "RANGE: 0x%08x -- 0x%08x ",
m->m_memory, m->m_memory + m->m_size - 1);
(void) fflush (stderr);
/* Peek at the surrounding longs,
for debugging a particular malloc
implementation. Your choices may
vary. */
fprintf (stderr, "BOUNDARY TAGS: %4d ", * (long *) (m->m_memory - 4));
(void) fflush (stderr);
fprintf (stderr, "%4d\n", * (long *) ((m->m_memory - 8) - (* (long *) (m->m_memory - 4))));
(void) fflush (stderr);
}
fprintf (stderr, "END DUMP_EVENTS\n");
(void) fflush (stderr);
} /* dump_events */
#endif DBG