home *** CD-ROM | disk | FTP | other *** search
- /* Fragit.c -- A simple memory thrasher/debugging tool.
- *
- * Copyright 1988 by Justin V. McCormick.
- * May be freely used, modified, and distributed in any for for either
- * commercial or personal profit or non-profit, so long as this notice
- * remains prominently attached to the source code.
- *
- * In any case, the author makes no specific performance claims
- * for this code and has no plans to maintain or support this code.
- * Additionally, the author bears no liability or responsibility if the
- * use of this code causes loss of data or sleep. This is your final
- * notice -- you've been warned!
- */
-
- /* Includes */
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/lists.h>
- #include <exec/memory.h>
- #include <exec/ports.h>
- #include <exec/io.h>
- #include <exec/libraries.h>
- #include <exec/interrupts.h>
- #include <exec/semaphores.h>
- #include <graphics/gfx.h>
- #include <graphics/view.h>
- #include <graphics/rastport.h>
- #include <graphics/layers.h>
- #include <graphics/clip.h>
- #include <graphics/text.h>
- #include <libraries/dos.h>
- #include <devices/timer.h>
- #include <devices/inputevent.h>
- #include <intuition/intuition.h>
- #include <intuition/intuitionbase.h>
- #include <intuition/screens.h>
- #include <ctype.h>
-
- /* External Functions */
- extern struct Library *OpenLibrary();
- extern VOID CloseLibrary();
- extern struct Window *OpenWindow();
- extern VOID CloseWindow();
- extern struct Node *RemHead();
- extern struct Node *RemTail();
- extern struct Message *GetMsg();
- extern VOID ReplyMsg();
- extern BYTE *AllocMem();
- extern VOID AddHead();
- extern VOID FreeMem();
- extern LONG AvailMem();
- extern LONG *DateStamp();
- extern LONG RangeRand();
- extern LONG atol();
-
- /* External Variables */
- extern WORD Enable_Abort;
-
- /* Local Definitions */
-
- /* Local Structure Definitions */
- struct FragNode /* For dynamic list of memory blocks */
- {
- struct MinNode fn_Node; /* Exec node linkage */
- ULONG fn_Size; /* Size of allocated block */
- BYTE *fn_Data; /* Pointer to allocated block */
- };
-
- /* Local Functions */
- WORD main();
- VOID ThrashMem();
- LONG AddRandomFrag();
- LONG FreeRandomFrag();
- struct MinList *AllocMinList();
- VOID FreeMinList();
- struct FragNode *AllocFragNode();
- VOID PrintMemoryStats();
- VOID FreeFragNode();
- VOID FreeAllFragNodes();
- VOID ShowUsage();
- VOID CleanUp();
- VOID RattleDice();
- WORD GetIDCMPEvents();
-
- /* Global Variables */
- struct GfxBase *GfxBase = 0L;
- struct IntuitionBase *IntuitionBase = 0L;
- struct MinList *FragList = 0L;
- struct Window *FragWin = 0L;
- UBYTE FragWinTitle[] = "Fragit 1.0 \xa9 1988 Justin V. McCormick";
- struct NewWindow NewWin =
- {
- 0,0,400,64,(UBYTE)0,(UBYTE)1,(ULONG)CLOSEWINDOW|RAWKEY,
- (ULONG)WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|SMART_REFRESH|NOCAREREFRESH,
- 0L,0L,FragWinTitle,0L,0L,0,0,0,0,(UWORD)WBENCHSCREEN
- };
- LONG AllocCount; /* Number of FragNodes in list */
- LONG FailCount; /* Number of allocs that failed */
- LONG TotalFragBytes; /* Number of bytes due to fn_Data frags */
- WORD Verbose; /* Verbose output flag */
-
- /* -------------------------------------------------------------------- */
- /* Program entry point. */
- /* -------------------------------------------------------------------- */
- WORD main(argc, argv)
- WORD argc;
- BYTE **argv;
- {
- BYTE tstr[80];
- WORD argindex;
- register LONG minmem, minfrag, maxfrag;
-
- /* Disable ^C processing */
- Enable_Abort = 0;
-
- /* Open libraries */
- if ( (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L)) == 0L)
- CleanUp("No GfxBase?");
- if ( (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0L)) == 0L)
- CleanUp("No IntuitionBase?");
-
- /* Set defaults, parse CLI arguments */
- minmem = 100000L;
- maxfrag = 10000L;
- minfrag = 8L;
- Verbose = 0;
- argindex = 1;
- if (argc > argindex)
- {
- if (argv[argindex][0] == '-' && (WORD)_tolower(argv[argindex][1]) == (WORD)'v')
- {
- Verbose = 1;
- argindex++;
- }
- if (argc > argindex)
- {
- if (isdigit(argv[argindex][0]) == 0)
- ShowUsage();
- minmem = atol(argv[argindex]);
- if (minmem <= 0L || minmem > 16000000L)
- {
- sprintf(tstr, "Minimum memory level '%ld' out of range.", minmem);
- CleanUp(tstr);
- }
- argindex++;
-
- if (argc > argindex)
- {
- if (isdigit(argv[argindex][0]) == 0)
- ShowUsage();
- minfrag = atol(argv[argindex]);
- if (minfrag <= 0L || minfrag > 16000000L)
- {
- sprintf(tstr, "Minimum fragment size '%ld' out of range.", minfrag);
- CleanUp(tstr);
- }
- argindex++;
-
- if (argc > argindex)
- {
- if (isdigit(argv[argindex][0]) == 0)
- ShowUsage();
- maxfrag = atol(argv[argindex]);
- if (maxfrag <= 0L || maxfrag > 16000000L)
- {
- sprintf(tstr, "Maximum fragment size '%ld' out of range.", maxfrag);
- CleanUp(tstr);
- }
- if (maxfrag < minfrag)
- {
- sprintf(tstr, "Maximum fragment size '%ld' less than Minumum size '%ld'!", maxfrag, minfrag);
- CleanUp(tstr);
- }
- }
- }
- }
- }
-
- /* Init RangeRand() seed */
- RattleDice();
-
- /* Open control window */
- if ( (FragWin = OpenWindow(&NewWin)) == 0L)
- CleanUp("Can't open window!");
-
- /* Feedback the post-parsed args, and give them time to read it */
- if (Verbose)
- printf("MinMemLevel: %ld MinFragSize: %ld MaxFragSize: %ld\n", minmem, minfrag, maxfrag);
- Delay(50L);
-
- /* Perform thrash function using "minmem" as the lowest number of bytes that
- * we will allow before freeing a memory fragment, and using "maxfrag" as
- * the largest sized memory fragment to be randomly allocated
- */
- ThrashMem(minmem, minfrag, maxfrag);
-
- /* All done, free everything */
- CleanUp("Done.");
- }
-
- /* -------------------------------------------------------------------- */
- /* Play with random sized memory chunks, where: */
- /* minfrag <= random size <= maxfrag */
- /* -------------------------------------------------------------------- */
- VOID ThrashMem(minmem, minfrag, maxfrag)
- register LONG minmem, minfrag, maxfrag;
- {
- register WORD done;
-
- /* Allocate and initialize MinList of FragNode fragments */
- if ( (FragList = AllocMinList()) == 0L)
- {
- printf("No RAM for MinList structure?");
- CleanUp();
- }
-
- /* Init variables, start thrash loop */
- done = 0;
- FailCount = AllocCount = TotalFragBytes = 0L;
- while (!done)
- {
- /* Update ram statistics in TitleBar */
- PrintMemoryStats();
-
- /* If available ram is greater than "minmem", attempt to allocate a random
- * sized fragment and add it to the MinList. Otherwise, free an entry
- * picked at random from the linked-list of FragNodes.
- */
- if (AvailMem((LONG)MEMF_PUBLIC) < minmem)
- {
- (VOID)FreeRandomFrag(FragList);
- }
- else
- {
- (VOID)AddRandomFrag(FragList, minfrag, maxfrag);
- }
-
- /* Check for exit conditions */
- done = GetIDCMPEvents(FragWin->UserPort);
-
- /* Crudely give other tasks a chance to run */
- Delay(1L);
- }
- }
-
- /* -------------------------------------------------------------------- */
- /* Show current fragmentation and memory statistics in FragWin window */
- /* -------------------------------------------------------------------- */
- VOID PrintMemoryStats()
- {
- BYTE tstr[80];
- static BYTE fmtstr1[] = "Frags: %4ld Fails: %4ld Allocated: %7ld";
- static BYTE fmtstr2[] = "Type Available Largest";
- static BYTE fmtstr3[] = "chip %7ld %7ld";
- static BYTE fmtstr4[] = "fast %7ld %7ld";
- static BYTE fmtstr5[] = "total %7ld %7ld";
- LONG chipavail, chiplargest;
- LONG fastavail, fastlargest;
- LONG totalavail, abslargest;
- register struct RastPort *rp;
-
- Forbid();
- chipavail = AvailMem(MEMF_CHIP);
- chiplargest = AvailMem(MEMF_CHIP|MEMF_LARGEST);
- fastavail = AvailMem(MEMF_FAST);
- fastlargest = AvailMem(MEMF_FAST|MEMF_LARGEST);
- Permit();
-
- totalavail = chipavail + fastavail;
- if (chiplargest > fastlargest)
- abslargest = chiplargest;
- else
- abslargest = fastlargest;
-
- sprintf(tstr, fmtstr1, AllocCount, FailCount, TotalFragBytes);
- rp = FragWin->RPort;
- SetAPen(rp, 1L);
- Move(rp, 24L, 20L);
- Text(rp, tstr, (LONG)strlen(tstr));
-
- SetAPen(rp, 3L);
- Move(rp, 90L, 30L);
- Text(rp, fmtstr2, (LONG)strlen(fmtstr2));
-
- SetAPen(rp, 1L);
- sprintf(tstr, fmtstr3, chipavail, chiplargest);
- Move(rp, 90L, 40L);
- Text(rp, tstr, (LONG)strlen(tstr));
-
- sprintf(tstr, fmtstr4, fastavail, fastlargest);
- Move(rp, 90L, 50L);
- Text(rp, tstr, (LONG)strlen(tstr));
-
- sprintf(tstr, fmtstr5, totalavail, abslargest);
- Move(rp, 90L, 60L);
- Text(rp, tstr, (LONG)strlen(tstr));
- }
-
- /* -------------------------------------------------------------------- */
- /* Given pointer to MinList and a maximum fragment size, allocate a */
- /* FragNode with a fragment size minfrag <= size <= maxfrag and insert */
- /* it at the head of the FragNode list. Return actual size of fragment. */
- /* -------------------------------------------------------------------- */
- LONG AddRandomFrag(list, minfrag, maxfrag)
- struct MinList *list;
- LONG minfrag, maxfrag;
- {
- register struct FragNode *tnode;
- register LONG tsize;
-
- if (minfrag == maxfrag)
- tsize = minfrag;
- else
- tsize = RangeRand(maxfrag - minfrag) + minfrag;
- tnode = AllocFragNode(tsize); /* alloc a random sized node */
- tsize += (LONG)sizeof(struct FragNode); /* account for struct size! */
-
- if (tnode != 0L)
- {
- AddHead(list, tnode);
- if (Verbose)
- printf("Adding a %7ld byte frag SUCCEEDED\n", tsize);
- AllocCount++;
- TotalFragBytes += tsize;
- return(tsize);
- }
- else
- {
- if (Verbose)
- printf("Adding a %7ld byte frag FAILED!\n", tsize);
- FailCount++;
- return(0L);
- }
- }
-
- /* -------------------------------------------------------------------- */
- /* Given a pointer to a MinList of FragNodes, remove one FragNode */
- /* at random from the list, deallocate it, and return the fragment */
- /* size that was deallocated. Return NULL (0L) if the list is empty. */
- /* -------------------------------------------------------------------- */
- LONG FreeRandomFrag(list)
- struct MinList *list;
- {
- register LONG i, j;
- register struct FragNode *tnode;
-
- /* Empty list! just return NULL */
- if (list->mlh_TailPred == list)
- return(0L);
-
- /* Generate a random number N, such that 0L <= N <= 99L */
- j = RangeRand(100L);
-
- /* Search through the MinList N times, restarting at lh_Head if we
- * hit the end of the list before finding the Nth node.
- */
- tnode = (struct FragNode *)list->mlh_Head;
- for (i = 0L; i < j; i++)
- {
- tnode = (struct FragNode *)tnode->fn_Node.mln_Succ;
- if (tnode == 0L)
- tnode = (struct FragNode *)list->mlh_Head;
- }
-
- /* Remove this node from the list, grab it's size and deallocate */
- Remove(tnode);
- i = tnode->fn_Size + (LONG)sizeof(struct FragNode);
- if (Verbose)
- printf("Freeing %7ld byte frag (0x%08lx)\n", i, tnode->fn_Data);
- FreeFragNode(tnode);
- AllocCount--;
- TotalFragBytes -= i;
-
- /* Return the actual size of fragment deallocated */
- return(i);
- }
-
- /* -------------------------------------------------------------------- */
- /* Given a IntuiMsgPort, process IDCMP messages received. If we get */
- /* a RAWKEY == RETURN, RAWKEY == ESCAPE, or CLOSEWINDOW event, return */
- /* TRUE (1). Else, return FALSE (0).
- /* -------------------------------------------------------------------- */
- WORD GetIDCMPEvents(userport)
- register struct IntuiMessage *userport;
- {
- register struct IntuiMessage *imsg;
- register ULONG class;
- register UWORD code;
- register UWORD qualifier;
- register WORD retval;
-
- retval = 0;
- while ( (imsg = (struct IntuiMessage *)GetMsg(userport)) != 0L)
- {
- class = imsg->Class;
- code = imsg->Code;
- qualifier = imsg->Qualifier;
- ReplyMsg(imsg);
-
- switch (class)
- {
- case RAWKEY:
- if (code == 0xc4 || code == 0xc5)
- retval = 1;
- break;
- case CLOSEWINDOW:
- retval = 1;
- break;
- }
-
- }
- return (retval);
- }
-
- /* -------------------------------------------------------------------- */
- /* Allocate and initialize a MinList structure, return pointer to same. */
- /* -------------------------------------------------------------------- */
- struct MinList *AllocMinList()
- {
- register struct MinList *mlist;
-
- mlist = (struct MinList *)AllocMem((LONG)sizeof(struct MinList), MEMF_PUBLIC);
- if (mlist)
- NewList(mlist);
- return(mlist);
- }
-
- /* -------------------------------------------------------------------- */
- /* Free memory allocated to a MinList structure, if allocated. */
- /* -------------------------------------------------------------------- */
- VOID FreeMinList(list)
- struct MinList *list;
- {
- if (list)
- FreeMem(list, (LONG)sizeof(struct MinList));
- }
-
- /* -------------------------------------------------------------------- */
- /* Allocate and initialize a FragNode structure, return pointer or 0L */
- /* -------------------------------------------------------------------- */
- struct FragNode *AllocFragNode(datasize)
- LONG datasize;
- {
- register struct FragNode *mnode;
-
- mnode = (struct FragNode *)AllocMem(datasize + (LONG)sizeof(struct FragNode), MEMF_PUBLIC);
- if (mnode != 0L)
- {
- mnode->fn_Size = datasize;
- mnode->fn_Data = (BYTE *)((LONG)mnode + (LONG)sizeof(struct FragNode));
- }
- return(mnode);
- }
-
- /* -------------------------------------------------------------------- */
- /* Free memory allocated to a FragNode structure, if allocated. */
- /* -------------------------------------------------------------------- */
- VOID FreeFragNode(mnode)
- struct FragNode *mnode;
- {
- if (mnode)
- FreeMem(mnode, (LONG)sizeof(struct FragNode) + mnode->fn_Size);
- }
-
- /* -------------------------------------------------------------------- */
- /* Walk list of allocated FragNodes in a MinList and free each one, */
- /* then deallocate the MinList itself. */
- /* -------------------------------------------------------------------- */
- VOID FreeAllFragNodes(list)
- struct List *list;
- {
- register struct FragNode *tnode;
-
- if (list)
- {
- while ( (tnode = (struct FragNode *)RemHead(list)) != 0L)
- FreeFragNode(tnode);
- FreeMinList(list);
- }
- }
-
- /* -------------------------------------------------------------------- */
- /* If CLI, print usage and exit. If Workbench, exit cleanly. */
- /* -------------------------------------------------------------------- */
- VOID ShowUsage()
- {
- CleanUp(\
- "Version 1.0 - Dynamic memory thrasher.\n\
- Copyright \xa9 1988 by Justin V. McCormick - Freely Redistributable\n\n\
- \x9b1;33;40mUsage:\x9b0m Fragit [-verbose] [MinMemLevel] [MinFragSize] [MaxFragSize]\n\
- Default Parameters: (100000) (12) (10000)\n" );
-
- }
-
- /* -------------------------------------------------------------------- */
- /* Universal exit point for entire program. */
- /* -------------------------------------------------------------------- */
- VOID CleanUp(exitmsg)
- BYTE *exitmsg;
- {
- if (exitmsg && Output() != 0L)
- printf("\x9b1;33;40mFragit:\x9b0m %s\n", exitmsg);
-
- FreeAllFragNodes(FragList);
- if (FragWin)
- CloseWindow(FragWin);
- if (IntuitionBase)
- CloseLibrary(IntuitionBase);
- if (GfxBase)
- CloseLibrary(GfxBase);
- exit(0);
- }
-
- /* -------------------------------------------------------------------- */
- /* Attempt to make RangeRand() a little less predictable between runs. */
- /* -------------------------------------------------------------------- */
- VOID RattleDice()
- {
- struct DateStamp stime;
- register WORD i, j;
- register LONG seedval;
-
- DateStamp(&stime);
- seedval = stime.ds_Tick;
- j = (WORD)RangeRand(seedval + 0xaa) & 0xff;
- for (i = 0; i < j; i++)
- (VOID)RangeRand(seedval);
- }
-