home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 160.lha / Fragit / fragit.c < prev    next >
C/C++ Source or Header  |  1988-04-27  |  16KB  |  529 lines

  1. /* Fragit.c -- A simple memory thrasher/debugging tool.
  2.  *
  3.  * Copyright 1988 by Justin V. McCormick.
  4.  *  May be freely used, modified, and distributed in any for for either
  5.  * commercial or personal profit or non-profit, so long as this notice
  6.  * remains prominently attached to the source code.
  7.  *
  8.  *  In any case, the author makes no specific performance claims
  9.  * for this code and has no plans to maintain or support this code.
  10.  * Additionally, the author bears no liability or responsibility if the
  11.  * use of this code causes loss of data or sleep.  This is your final
  12.  * notice -- you've been warned!
  13.  */
  14.  
  15. /* Includes */
  16. #include <exec/types.h>
  17. #include <exec/nodes.h>
  18. #include <exec/lists.h>
  19. #include <exec/memory.h>
  20. #include <exec/ports.h>
  21. #include <exec/io.h>
  22. #include <exec/libraries.h>
  23. #include <exec/interrupts.h>
  24. #include <exec/semaphores.h>
  25. #include <graphics/gfx.h>
  26. #include <graphics/view.h>
  27. #include <graphics/rastport.h>
  28. #include <graphics/layers.h>
  29. #include <graphics/clip.h>
  30. #include <graphics/text.h>
  31. #include <libraries/dos.h>
  32. #include <devices/timer.h>
  33. #include <devices/inputevent.h>
  34. #include <intuition/intuition.h>
  35. #include <intuition/intuitionbase.h>
  36. #include <intuition/screens.h>
  37. #include <ctype.h>
  38.  
  39. /* External Functions */
  40. extern struct Library *OpenLibrary();
  41. extern VOID CloseLibrary();
  42. extern struct Window *OpenWindow();
  43. extern VOID CloseWindow();
  44. extern struct Node *RemHead();
  45. extern struct Node *RemTail();
  46. extern struct Message *GetMsg();
  47. extern VOID ReplyMsg();
  48. extern BYTE *AllocMem();
  49. extern VOID AddHead();
  50. extern VOID FreeMem();
  51. extern LONG AvailMem();
  52. extern LONG *DateStamp();
  53. extern LONG RangeRand();
  54. extern LONG atol();
  55.  
  56. /* External Variables */
  57. extern WORD Enable_Abort;
  58.  
  59. /* Local Definitions */
  60.  
  61. /* Local Structure Definitions */
  62. struct FragNode            /* For dynamic list of memory blocks    */
  63. {
  64.   struct MinNode fn_Node;    /* Exec node linkage            */
  65.   ULONG fn_Size;        /* Size of allocated block        */
  66.   BYTE *fn_Data;        /* Pointer to allocated block        */
  67. };
  68.  
  69. /* Local Functions */
  70. WORD main();
  71. VOID ThrashMem();
  72. LONG AddRandomFrag();
  73. LONG FreeRandomFrag();
  74. struct MinList *AllocMinList();
  75. VOID FreeMinList();
  76. struct FragNode *AllocFragNode();
  77. VOID PrintMemoryStats();
  78. VOID FreeFragNode();
  79. VOID FreeAllFragNodes();
  80. VOID ShowUsage();
  81. VOID CleanUp();
  82. VOID RattleDice();
  83. WORD GetIDCMPEvents();
  84.  
  85. /* Global Variables */
  86. struct GfxBase *GfxBase = 0L;
  87. struct IntuitionBase *IntuitionBase = 0L;
  88. struct MinList *FragList = 0L;
  89. struct Window *FragWin = 0L;
  90. UBYTE FragWinTitle[] = "Fragit 1.0 \xa9 1988 Justin V. McCormick";
  91. struct NewWindow NewWin =
  92. {
  93.   0,0,400,64,(UBYTE)0,(UBYTE)1,(ULONG)CLOSEWINDOW|RAWKEY,
  94.   (ULONG)WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|SMART_REFRESH|NOCAREREFRESH,
  95.   0L,0L,FragWinTitle,0L,0L,0,0,0,0,(UWORD)WBENCHSCREEN
  96. };
  97. LONG AllocCount;        /* Number of FragNodes in list        */
  98. LONG FailCount;            /* Number of allocs that failed     */
  99. LONG TotalFragBytes;        /* Number of bytes due to fn_Data frags    */
  100. WORD Verbose;            /* Verbose output flag            */
  101.  
  102. /* -------------------------------------------------------------------- */
  103. /* Program entry point.                            */
  104. /* -------------------------------------------------------------------- */
  105. WORD main(argc, argv)
  106.   WORD argc;
  107.   BYTE **argv;
  108. {
  109.   BYTE tstr[80];
  110.   WORD argindex;
  111.   register LONG minmem, minfrag, maxfrag;
  112.  
  113. /* Disable ^C processing */
  114.   Enable_Abort = 0;
  115.  
  116. /* Open libraries */
  117.   if ( (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0L)) == 0L)
  118.     CleanUp("No GfxBase?");
  119.   if ( (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0L)) == 0L)
  120.     CleanUp("No IntuitionBase?");
  121.  
  122. /* Set defaults, parse CLI arguments */
  123.   minmem = 100000L;
  124.   maxfrag = 10000L;
  125.   minfrag = 8L;
  126.   Verbose = 0;
  127.   argindex = 1;
  128.   if (argc > argindex)
  129.   {
  130.     if (argv[argindex][0] == '-' && (WORD)_tolower(argv[argindex][1]) == (WORD)'v')
  131.     {
  132.       Verbose = 1;
  133.       argindex++;
  134.     }
  135.     if (argc > argindex)
  136.     {
  137.       if (isdigit(argv[argindex][0]) == 0)
  138.         ShowUsage();
  139.       minmem = atol(argv[argindex]);
  140.       if (minmem <= 0L || minmem > 16000000L)
  141.       {
  142.         sprintf(tstr, "Minimum memory level '%ld' out of range.", minmem);
  143.         CleanUp(tstr);
  144.       }
  145.       argindex++;
  146.  
  147.       if (argc > argindex)
  148.       {
  149.         if (isdigit(argv[argindex][0]) == 0)
  150.           ShowUsage();
  151.         minfrag = atol(argv[argindex]);
  152.         if (minfrag <= 0L || minfrag > 16000000L)
  153.         {
  154.           sprintf(tstr, "Minimum fragment size '%ld' out of range.", minfrag);
  155.           CleanUp(tstr);
  156.         }
  157.         argindex++;
  158.  
  159.         if (argc > argindex)
  160.         {
  161.           if (isdigit(argv[argindex][0]) == 0)
  162.             ShowUsage();
  163.           maxfrag = atol(argv[argindex]);
  164.           if (maxfrag <= 0L || maxfrag > 16000000L)
  165.           {
  166.             sprintf(tstr, "Maximum fragment size '%ld' out of range.", maxfrag);
  167.             CleanUp(tstr);
  168.           }
  169.           if (maxfrag < minfrag)
  170.           {
  171.             sprintf(tstr, "Maximum fragment size '%ld' less than Minumum size '%ld'!", maxfrag, minfrag);
  172.             CleanUp(tstr);
  173.           }
  174.         }
  175.       }
  176.     }
  177.   }
  178.  
  179. /* Init RangeRand() seed */
  180.   RattleDice();
  181.  
  182. /* Open control window */
  183.   if ( (FragWin = OpenWindow(&NewWin)) == 0L)
  184.     CleanUp("Can't open window!");
  185.  
  186. /* Feedback the post-parsed args, and give them time to read it */
  187.   if (Verbose)
  188.     printf("MinMemLevel: %ld MinFragSize: %ld MaxFragSize: %ld\n", minmem, minfrag, maxfrag);
  189.   Delay(50L);
  190.  
  191. /* Perform thrash function using "minmem" as the lowest number of bytes that
  192.  * we will allow before freeing a memory fragment, and using "maxfrag" as
  193.  * the largest sized memory fragment to be randomly allocated
  194.  */
  195.   ThrashMem(minmem, minfrag, maxfrag);
  196.  
  197. /* All done, free everything */
  198.   CleanUp("Done.");
  199. }
  200.  
  201. /* -------------------------------------------------------------------- */
  202. /* Play with random sized memory chunks, where:                */
  203. /*   minfrag <= random size <= maxfrag                    */
  204. /* -------------------------------------------------------------------- */
  205. VOID ThrashMem(minmem, minfrag, maxfrag)
  206.   register LONG minmem, minfrag, maxfrag;
  207. {
  208.   register WORD done;
  209.  
  210. /* Allocate and initialize MinList of FragNode fragments */
  211.   if ( (FragList = AllocMinList()) == 0L)
  212.   {
  213.     printf("No RAM for MinList structure?");
  214.     CleanUp();
  215.   }
  216.  
  217. /* Init variables, start thrash loop */
  218.   done = 0;
  219.   FailCount = AllocCount = TotalFragBytes = 0L;
  220.   while (!done)
  221.   {
  222. /* Update ram statistics in TitleBar */
  223.     PrintMemoryStats();
  224.  
  225. /* If available ram is greater than "minmem", attempt to allocate a random
  226.  * sized fragment and add it to the MinList.  Otherwise, free an entry
  227.  * picked at random from the linked-list of FragNodes.
  228.  */
  229.     if (AvailMem((LONG)MEMF_PUBLIC) < minmem)
  230.     {
  231.       (VOID)FreeRandomFrag(FragList);
  232.     }
  233.     else
  234.     {
  235.       (VOID)AddRandomFrag(FragList, minfrag, maxfrag);
  236.     }
  237.  
  238. /* Check for exit conditions */
  239.     done = GetIDCMPEvents(FragWin->UserPort);
  240.  
  241. /* Crudely give other tasks a chance to run */
  242.     Delay(1L);
  243.   }
  244. }
  245.  
  246. /* -------------------------------------------------------------------- */
  247. /* Show current fragmentation and memory statistics in FragWin window    */
  248. /* -------------------------------------------------------------------- */
  249. VOID PrintMemoryStats()
  250. {
  251.   BYTE tstr[80];
  252.   static BYTE fmtstr1[] = "Frags: %4ld  Fails: %4ld  Allocated: %7ld";
  253.   static BYTE fmtstr2[] = "Type  Available   Largest";
  254.   static BYTE fmtstr3[] = "chip    %7ld   %7ld";
  255.   static BYTE fmtstr4[] = "fast    %7ld   %7ld";
  256.   static BYTE fmtstr5[] = "total   %7ld   %7ld";
  257.   LONG chipavail, chiplargest;
  258.   LONG fastavail, fastlargest;
  259.   LONG totalavail, abslargest;
  260.   register struct RastPort *rp;
  261.  
  262.   Forbid();
  263.   chipavail = AvailMem(MEMF_CHIP);
  264.   chiplargest = AvailMem(MEMF_CHIP|MEMF_LARGEST);
  265.   fastavail = AvailMem(MEMF_FAST);
  266.   fastlargest = AvailMem(MEMF_FAST|MEMF_LARGEST);
  267.   Permit();
  268.  
  269.   totalavail = chipavail + fastavail;
  270.   if (chiplargest > fastlargest)
  271.     abslargest = chiplargest;
  272.   else
  273.     abslargest = fastlargest;
  274.   
  275.   sprintf(tstr, fmtstr1, AllocCount, FailCount, TotalFragBytes);
  276.   rp = FragWin->RPort;
  277.   SetAPen(rp, 1L);
  278.   Move(rp, 24L, 20L);
  279.   Text(rp, tstr, (LONG)strlen(tstr));
  280.  
  281.   SetAPen(rp, 3L);
  282.   Move(rp, 90L, 30L);
  283.   Text(rp, fmtstr2, (LONG)strlen(fmtstr2));
  284.  
  285.   SetAPen(rp, 1L);
  286.   sprintf(tstr, fmtstr3, chipavail, chiplargest);
  287.   Move(rp, 90L, 40L);
  288.   Text(rp, tstr, (LONG)strlen(tstr));
  289.  
  290.   sprintf(tstr, fmtstr4, fastavail, fastlargest);
  291.   Move(rp, 90L, 50L);
  292.   Text(rp, tstr, (LONG)strlen(tstr));
  293.  
  294.   sprintf(tstr, fmtstr5, totalavail, abslargest);
  295.   Move(rp, 90L, 60L);
  296.   Text(rp, tstr, (LONG)strlen(tstr));
  297. }
  298.  
  299. /* -------------------------------------------------------------------- */
  300. /* Given pointer to MinList and a maximum fragment size, allocate a    */
  301. /* FragNode with a fragment size minfrag <= size <= maxfrag and insert    */
  302. /* it at the head of the FragNode list.    Return actual size of fragment.    */
  303. /* -------------------------------------------------------------------- */
  304. LONG AddRandomFrag(list, minfrag, maxfrag)
  305.   struct MinList *list;
  306.   LONG minfrag, maxfrag;
  307. {
  308.   register struct FragNode *tnode;
  309.   register LONG tsize;
  310.  
  311.   if (minfrag == maxfrag)
  312.     tsize = minfrag;
  313.   else
  314.     tsize = RangeRand(maxfrag - minfrag) + minfrag;
  315.   tnode = AllocFragNode(tsize);            /* alloc a random sized node     */
  316.   tsize += (LONG)sizeof(struct FragNode);    /* account for struct size!     */
  317.  
  318.   if (tnode != 0L)
  319.   {
  320.     AddHead(list, tnode);
  321.     if (Verbose)
  322.       printf("Adding a %7ld byte frag SUCCEEDED\n", tsize);
  323.     AllocCount++;
  324.     TotalFragBytes += tsize;
  325.     return(tsize);
  326.   }
  327.   else
  328.   {
  329.     if (Verbose)
  330.       printf("Adding a %7ld byte frag FAILED!\n", tsize);
  331.     FailCount++;
  332.     return(0L);
  333.   }
  334. }
  335.  
  336. /* -------------------------------------------------------------------- */
  337. /* Given a pointer to a MinList of FragNodes, remove one FragNode    */
  338. /* at random from the list, deallocate it, and return the fragment    */
  339. /* size that was deallocated.  Return NULL (0L) if the list is empty.    */
  340. /* -------------------------------------------------------------------- */
  341. LONG FreeRandomFrag(list)
  342.   struct MinList *list;
  343. {
  344.   register LONG i, j;
  345.   register struct FragNode *tnode;
  346.  
  347. /* Empty list! just return NULL */
  348.   if (list->mlh_TailPred == list)
  349.     return(0L);
  350.  
  351. /* Generate a random number N, such that 0L <= N <= 99L */
  352.   j = RangeRand(100L);
  353.  
  354. /* Search through the MinList N times, restarting at lh_Head if we
  355.  * hit the end of the list before finding the Nth node.
  356.  */
  357.   tnode = (struct FragNode *)list->mlh_Head;
  358.   for (i = 0L; i < j; i++)
  359.   {
  360.     tnode = (struct FragNode *)tnode->fn_Node.mln_Succ;
  361.     if (tnode == 0L)
  362.       tnode = (struct FragNode *)list->mlh_Head;
  363.   }
  364.  
  365. /* Remove this node from the list, grab it's size and deallocate */
  366.   Remove(tnode);
  367.   i = tnode->fn_Size + (LONG)sizeof(struct FragNode);
  368.   if (Verbose)
  369.     printf("Freeing  %7ld byte frag (0x%08lx)\n", i, tnode->fn_Data);
  370.   FreeFragNode(tnode);
  371.   AllocCount--;
  372.   TotalFragBytes -= i;
  373.  
  374. /* Return the actual size of fragment deallocated */
  375.   return(i);
  376. }
  377.  
  378. /* -------------------------------------------------------------------- */
  379. /* Given a IntuiMsgPort, process IDCMP messages received.  If we get    */
  380. /* a RAWKEY == RETURN, RAWKEY == ESCAPE, or CLOSEWINDOW event, return    */
  381. /* TRUE (1).  Else, return FALSE (0).
  382. /* -------------------------------------------------------------------- */
  383. WORD GetIDCMPEvents(userport)
  384.   register struct IntuiMessage *userport;
  385. {
  386.   register struct IntuiMessage *imsg;
  387.   register ULONG class;
  388.   register UWORD code;
  389.   register UWORD qualifier;
  390.   register WORD retval;
  391.  
  392.   retval = 0;
  393.   while ( (imsg = (struct IntuiMessage *)GetMsg(userport)) != 0L)
  394.   {
  395.     class = imsg->Class;
  396.     code = imsg->Code;
  397.     qualifier = imsg->Qualifier;
  398.     ReplyMsg(imsg);
  399.  
  400.     switch (class)
  401.     {
  402.       case RAWKEY:
  403.         if (code == 0xc4 || code == 0xc5)
  404.           retval = 1;
  405.         break;
  406.       case CLOSEWINDOW:
  407.         retval = 1;
  408.         break;
  409.     }
  410.  
  411.   }
  412.   return (retval);
  413. }
  414.  
  415. /* -------------------------------------------------------------------- */
  416. /* Allocate and initialize a MinList structure, return pointer to same.    */
  417. /* -------------------------------------------------------------------- */
  418. struct MinList *AllocMinList()
  419. {
  420.   register struct MinList *mlist;
  421.  
  422.   mlist = (struct MinList *)AllocMem((LONG)sizeof(struct MinList), MEMF_PUBLIC);
  423.   if (mlist)
  424.     NewList(mlist);
  425.   return(mlist);
  426. }
  427.  
  428. /* -------------------------------------------------------------------- */
  429. /* Free memory allocated to a MinList structure, if allocated.        */
  430. /* -------------------------------------------------------------------- */
  431. VOID FreeMinList(list)
  432.   struct MinList *list;
  433. {
  434.   if (list)
  435.     FreeMem(list, (LONG)sizeof(struct MinList));
  436. }
  437.  
  438. /* -------------------------------------------------------------------- */
  439. /* Allocate and initialize a FragNode structure, return pointer or 0L    */
  440. /* -------------------------------------------------------------------- */
  441. struct FragNode *AllocFragNode(datasize)
  442.   LONG datasize;
  443. {
  444.   register struct FragNode *mnode;
  445.  
  446.   mnode = (struct FragNode *)AllocMem(datasize + (LONG)sizeof(struct FragNode), MEMF_PUBLIC);
  447.   if (mnode != 0L)
  448.   {
  449.     mnode->fn_Size = datasize;
  450.     mnode->fn_Data = (BYTE *)((LONG)mnode + (LONG)sizeof(struct FragNode));
  451.   }
  452.   return(mnode);
  453. }
  454.  
  455. /* -------------------------------------------------------------------- */
  456. /* Free memory allocated to a FragNode structure, if allocated.        */
  457. /* -------------------------------------------------------------------- */
  458. VOID FreeFragNode(mnode)
  459.   struct FragNode *mnode;
  460. {
  461.   if (mnode)
  462.     FreeMem(mnode, (LONG)sizeof(struct FragNode) + mnode->fn_Size);
  463. }
  464.  
  465. /* -------------------------------------------------------------------- */
  466. /* Walk list of allocated FragNodes in a MinList and free each one,    */
  467. /* then deallocate the MinList itself.                     */
  468. /* -------------------------------------------------------------------- */
  469. VOID FreeAllFragNodes(list)
  470.   struct List *list;
  471. {
  472.   register struct FragNode *tnode;
  473.  
  474.   if (list)
  475.   {
  476.     while ( (tnode = (struct FragNode *)RemHead(list)) != 0L)
  477.       FreeFragNode(tnode);
  478.     FreeMinList(list);
  479.   }
  480. }
  481.  
  482. /* -------------------------------------------------------------------- */
  483. /* If CLI, print usage and exit.  If Workbench, exit cleanly.        */
  484. /* -------------------------------------------------------------------- */
  485. VOID ShowUsage()
  486. {
  487.   CleanUp(\
  488. "Version 1.0 - Dynamic memory thrasher.\n\
  489. Copyright \xa9 1988 by Justin V. McCormick - Freely Redistributable\n\n\
  490. \x9b1;33;40mUsage:\x9b0m Fragit [-verbose] [MinMemLevel] [MinFragSize] [MaxFragSize]\n\
  491.         Default Parameters: (100000)        (12)         (10000)\n" );
  492.  
  493. }
  494.  
  495. /* -------------------------------------------------------------------- */
  496. /* Universal exit point for entire program.                */
  497. /* -------------------------------------------------------------------- */
  498. VOID CleanUp(exitmsg)
  499.   BYTE *exitmsg;
  500. {
  501.   if (exitmsg && Output() != 0L)
  502.     printf("\x9b1;33;40mFragit:\x9b0m %s\n", exitmsg);
  503.  
  504.   FreeAllFragNodes(FragList);
  505.   if (FragWin)
  506.     CloseWindow(FragWin);
  507.   if (IntuitionBase)
  508.     CloseLibrary(IntuitionBase);
  509.   if (GfxBase)
  510.     CloseLibrary(GfxBase);
  511.   exit(0);
  512. }
  513.  
  514. /* -------------------------------------------------------------------- */
  515. /* Attempt to make RangeRand() a little less predictable between runs.    */
  516. /* -------------------------------------------------------------------- */
  517. VOID RattleDice()
  518. {
  519.   struct DateStamp stime;
  520.   register WORD i, j;
  521.   register LONG seedval;
  522.  
  523.   DateStamp(&stime);
  524.   seedval = stime.ds_Tick;
  525.   j = (WORD)RangeRand(seedval + 0xaa) & 0xff;
  526.   for (i = 0; i < j; i++)
  527.     (VOID)RangeRand(seedval);
  528. }
  529.