"I am a person who works hard and plays hard."

Yuan Wei
Second Year Graduate Student Department of Computer Science
University of Virginia Charlottesville, VA 22903
Email: yw3f@cs.virginia.edu


Source Code Analysis

Main Page   Compound List   File List   Compound Members   File Members  

facopt.c

Go to the documentation of this file.
00001 /************************************************************************
00002 * Copyright (C) 1989, 1990, 1991, 1992, 1993                            *
00003 *                   Rabin A. Sugumar and Santosh G. Abraham             *
00004 *                                                                       *
00005 * This software is distributed absolutely without warranty. You are     *
00006 * free to use and modify the software as you wish.  You are also free   *
00007 * to distribute the software as long as it is not for commercial gain,  *
00008 * you retain the above copyright notice, and you make clear what your   *
00009 * modifications were.                                                   *
00010 *                                                                       *
00011 * Send comments and bug reports to rabin@eecs.umich.edu                 *
00012 *                                                                       *
00013 ************************************************************************/
00014 
00015 /* Simulates fully associative caches of a range of sizes but of *
00016  * a constant line size with OPT replacement.                    */
00017 
00018 #include <stdio.h>
00019 #include <stdlib.h>
00020 
00021 #include "../host.h"
00022 #include "../misc.h"
00023 #include "../machine.h"
00024 #include "util.h"
00025 #include "libcheetah.h"
00026 
00027 /* Macros */
00028 #define toggle(i) if(i==1)i=0;else{i=1;}
00029 #define min(a,b) ((a<b) ? a : b)
00030 
00031 #define ONE 1
00032 #define MAX_PHYSICAL_MEM 2097152  /* Physical mem available on machine */
00033 #define BYTES_PER_LINE 35  /* Storage requirement per line */
00034 
00035 #define HASHNO 7211    /* number of slots in hash table */
00036 #define TREE_HEIGHT 50000  /* maximum height of tree */
00037 #define CACHE_SIZE 50000  /* no of lines in cache */
00038 #define MAXINT 2147483647   /* 2^31-1 */
00039 
00040 struct group_desc {
00041   struct tree_node *first;
00042   struct tree_node *last;
00043   int grpno;
00044   int wt;
00045   struct group_desc *nxt;
00046 };
00047 
00048 static struct group_desc headgrp;       /* Head of group list */
00049 static struct tree_node *root,  /* Root of tree */
00050                      **p_stack; /* Stack used in tree operations */
00051 static struct hash_table slot[HASHNO];  /* Hash table */
00052 static short slot_flag [HASHNO];        /* Flag for hash slots */
00053 static unsigned *out_stack;     /* Stack depth hits array */
00054 static int comp=0, comp_del=0, comp_ins=0,
00055            no_splay_steps, tot_addrs, grps_passd;
00056 static int t_entries;           /* Count of addresses processed */
00057 extern unsigned addr_array[],
00058                 time_array[];
00059 static int ihcount;  /* To count no of time inf_handler called */
00060 static int grp_ct=MAXINT;  /* To number groups */
00061 static short size_exceeded=0;           /* Stack overflow flag */
00062 static int log_tot_addrs;
00063 static unsigned next_two_pwr;
00064 static unsigned unknowns;
00065 
00066 static int CLEAN_INTERVAL,
00067            next_clean_time;
00068 
00069 extern int L,           /* Line size */
00070            T;           /* Max addresses processed */
00071 extern unsigned MAX_CACHE_SIZE, /* Maximum cache size of interest */
00072                 MAX_LINES;      /* Calculated from max cache size and line size */
00073 extern int MISS_RATIO_INTERVAL, /* Output interval */
00074            SAVE_INTERVAL,       /* Interval at which results are saved */
00075            P_INTERVAL;  /* Intervals at which progress output is done */
00076 
00077 static int next_save_time;
00078 
00079 
00080 /********************************************************************
00081 Given the index of the address in the address array it determines the
00082 priority of the address using the time_array.
00083 
00084 Input: Index of current address in the addr_array.
00085 Output: The priority of the current address
00086 Side effects: None
00087 ********************************************************************/
00088 int
00089 Priority_fa(int i)
00090 {
00091   static int inf_count = 0;
00092 
00093   /* inf_handler assumes this fn inf_handler has to be changed if this is
00094      changed */
00095   if (time_array[i] > 0)
00096     return (MAXINT - time_array[i]);
00097   else if (time_array[i] == 0)
00098     return --inf_count;
00099   else
00100     {
00101       fprintf(stderr, "libcheetah: error in Priority function\n");
00102       return 0;
00103     }
00104 }
00105 
00106 
00107 /**********************************************************************
00108 Used to add infinities to a hash table. The hash table is used by inf_handler
00109 to get the dummy priority of the unknown and its grptime.
00110 
00111 Input: The address, the current group number of the first group and
00112        the dummy prty of the address.
00113 Output: None
00114 Side effects: The address is added to the hash table
00115 **************************************************************************/
00116 void
00117 unk_hash_add_fa(md_addr_t addr, int grpno, int prty)
00118 {
00119   int loc;
00120   struct hash_table *ptr, *oldptr;
00121 
00122   ++unknowns;
00123 
00124   loc = addr % HASHNO;
00125   if (slot_flag[loc] == 0)
00126     {
00127       slot_flag[loc] = 1;
00128       slot[loc].addr = addr;
00129       slot[loc].grptime = grpno;
00130       slot[loc].prty = prty;
00131       slot[loc].nxt = NULL;
00132       return;
00133     }
00134   else
00135     {
00136       ptr = &slot[loc];
00137       while (ptr)
00138         {
00139           oldptr = ptr;
00140           if (ptr->addr == addr)
00141             {
00142               fprintf(stderr, "libcheetah: addr already in hash table\n"); 
00143               myfprintf(stderr,
00144                         "addr: 0x%p; t_entries: %u; prty: %d\n",
00145                         addr, t_entries, ptr->prty);
00146               myfprintf(stderr,
00147                         "slot addr: 0x%p; prty: %d\n",
00148                         slot[loc].addr, slot[loc].prty);
00149             }
00150           ptr = ptr->nxt;
00151         }
00152       if ((oldptr->nxt = UHT_Get_from_free_list ()) == NULL)
00153         {
00154           oldptr->nxt = calloc(1, sizeof(struct hash_table));
00155           if (!oldptr->nxt)
00156             fatal("out of virtual memory");
00157         }
00158       oldptr->nxt->addr = addr;
00159       oldptr->nxt->nxt = NULL;
00160       oldptr->nxt->grptime = grpno;
00161       oldptr->nxt->prty = prty;
00162       return;
00163     }
00164 }
00165 
00166 
00167 /*************************************************************************
00168 Deletes unknowns from the hash table. Returns the grptime and the dummy
00169 priority of the address.
00170 
00171 Input: Address
00172 Outpur: The grptime and the dummy priority
00173 Side effects: The entry is deleted from the hash table
00174 *************************************************************************/
00175 int
00176 unk_hash_del_fa(md_addr_t addr, int *prty_ptr)
00177 {
00178   int loc, grpno;
00179   struct hash_table *ptr, *oldptr;
00180 
00181   loc = addr % HASHNO;
00182   if (slot_flag[loc] == 0)
00183     return 0;
00184   else if (slot[loc].addr == addr)
00185     {
00186       if (slot[loc].nxt == NULL)
00187         {
00188           slot_flag[loc] = 0;
00189           *prty_ptr = slot[loc].prty;
00190           return slot[loc].grptime;
00191         }
00192       else
00193         {
00194           grpno = slot[loc].grptime;
00195           *prty_ptr = slot[loc].prty;
00196           slot[loc].addr = slot[loc].nxt->addr;
00197           slot[loc].grptime = slot[loc].nxt->grptime;
00198           slot[loc].prty = slot[loc].nxt->prty;
00199           ptr = slot[loc].nxt;
00200           slot[loc].nxt = slot[loc].nxt->nxt;
00201           UHT_Add_to_free_list(ptr);
00202           return grpno;
00203         }
00204     }
00205   else
00206     {
00207       ptr = &slot[loc];
00208       while (ptr)
00209         {
00210           if (ptr->addr == addr)
00211             break;
00212           oldptr = ptr;
00213           ptr = ptr->nxt;
00214         }
00215       if (ptr)
00216         {
00217           grpno = ptr->grptime;
00218           *prty_ptr = ptr->prty;
00219           oldptr->nxt = ptr->nxt;
00220           UHT_Add_to_free_list (ptr);
00221           return grpno;
00222         }
00223       else
00224         return 0;
00225     }
00226 }
00227 
00228 
00229 /******************************************************************
00230 Determines the maximum priority of an unknown in the stack by doing an
00231 inorder traversal of the tree.
00232 Adapted from Harry Smith "Data structures: Form and Function"
00233 
00234 Input: None
00235 Output: Maximum unknown priority in stack
00236 Side effects: None
00237 ******************************************************************/
00238 int
00239 Get_max_prty_unknown(void)
00240 {
00241   int top;
00242   struct tree_node *ptr;
00243   int max_prty = (5 - MAXINT);
00244 
00245   ptr = root;
00246   top = 0;
00247   while (ptr != NULL)
00248     {
00249       ++top;
00250       p_stack[top] = ptr;
00251       ptr = ptr->lft;
00252     }
00253    while (top > 0)
00254      {
00255        ptr = p_stack[top];
00256        --top;
00257        if ((ptr->prty < 0) && (ptr->prty > max_prty))
00258          max_prty = ptr->prty;
00259        if (ptr->rt != NULL)
00260          {
00261            ptr = ptr->rt;
00262            while (ptr != NULL)
00263              {
00264                ++top;
00265                p_stack[top] = ptr;
00266                ptr = ptr->lft;
00267              }
00268          }
00269      }
00270   return max_prty;
00271 }
00272 
00273 
00274 /***********************************************************************
00275 Cleans the unknown hash table. Get the maximum unknown priority in the
00276 stack by calling the routine Get_max_prty_unknown
00277 
00278 Input: None
00279 Output: None
00280 Side effects: Removes inessential unknowns from the hash table
00281 ***********************************************************************/
00282 void
00283 hash_clean_fa(void)
00284 {
00285   int loc,              /* Scratch */
00286         max_prty;       /* Max unknown priority in stack */
00287   struct hash_table *ptr, *oldptr;      /* Scratch */
00288 
00289   max_prty = Get_max_prty_unknown();
00290   if (max_prty >= 0)
00291     fprintf(stderr, "libcheetah: max unknown priority non-negative\n");
00292 
00293   for (loc=0; loc<HASHNO; loc++)
00294     {
00295       while ((slot_flag[loc] != 0) && (slot[loc].prty > max_prty))
00296         {
00297           --unknowns;
00298           if (slot[loc].nxt == NULL)
00299             {
00300               slot_flag[loc] = 0;
00301               continue;
00302             }
00303           else
00304             {
00305               slot[loc].addr = slot[loc].nxt->addr;
00306               slot[loc].grptime = slot[loc].nxt->grptime;
00307               slot[loc].prty = slot[loc].nxt->prty;
00308               ptr = slot[loc].nxt;
00309               slot[loc].nxt = slot[loc].nxt->nxt;
00310               UHT_Add_to_free_list(ptr);
00311             }
00312         } /* while */
00313       if (slot_flag[loc] != 0)
00314         {
00315           ptr = &slot[loc];
00316           while (ptr)
00317             {
00318               if (ptr->prty > max_prty)
00319                 {
00320                   --unknowns;
00321                   oldptr->nxt = ptr->nxt;
00322                   UHT_Add_to_free_list(ptr);
00323                   ptr = oldptr;
00324                 }
00325               oldptr = ptr;
00326               ptr = ptr->nxt;
00327             }
00328         }
00329     } /* for */
00330 }
00331 
00332 
00333 /********************************************************************
00334 Output routine.
00335 
00336 Input: None
00337 Output: None
00338 Side effects: None
00339 ********************************************************************/
00340 void
00341 outpr_facopt(FILE *fd)
00342 {
00343   int sum = 0, i;
00344   int stack_end;
00345 
00346   fprintf(fd, "Addresses processed : %d\n", t_entries);
00347   fprintf(fd, "Line size : %d bytes \n", (ONE << L));
00348   fprintf(fd, "Number of distinct addresses  %d\n", tot_addrs);
00349 #ifdef PERF
00350   fprintf(fd, "Total Number of groups passed\t%d\n\n", grps_passd);
00351   fprintf(fd, "Total Number of splay steps\t%d\n\n", no_splay_steps);
00352   fprintf(fd, "Number of insert comparisons\t%d\n", comp_ins);
00353   fprintf(fd, "Number of delete comparisons\t%d\n", comp_del);
00354   fprintf(fd, "Number of times inf_handler called\t%d\n", ihcount);
00355 #endif
00356 
00357   fprintf(fd, "Cache size (bytes)\tMiss Ratio\n");
00358   stack_end = min ((unsigned)tot_addrs, MAX_LINES);
00359    
00360   for (i = 1; i <= stack_end; i++)
00361     {
00362       sum += out_stack[i];
00363       if ((i % MISS_RATIO_INTERVAL) == 0)
00364         fprintf(fd, "%d\t\t\t%1.6f\n", (i * (ONE << L)),
00365                 (1.0 - ((double)sum/(double)t_entries)));
00366     }
00367   if (stack_end == tot_addrs)
00368     fprintf(fd, "Miss ratio is %f for all bigger caches\n",
00369             (1.0 - ((double)sum/(double)t_entries)));
00370   fprintf(fd, "\n\n\n");
00371 }
00372 
00373 
00374 /**********************************************************************
00375 Locates the referenced address, deletes it and inserts the address deleted
00376 from the previous group in its place.
00377 
00378 Input: Referenced address and address deleted from earlier group
00379 Output: Pointer to node at which insertion occurred.
00380 Side effects.: The deletion and insertion are done and the inserted
00381 node is splayed to the root of the tree.
00382 ***********************************************************************/
00383 struct tree_node *
00384 Lookup_Delete_Insert(struct tree_node *del_entry,       /* ent to delete */
00385                      struct tree_node *ins_entry)       /* deleted line */
00386 {
00387   struct tree_node *ptr, *inserted_node;
00388   int top, pos, at;
00389   int grpno, prty;
00390 
00391   grpno = del_entry->grpno;
00392   prty = del_entry->prty;
00393   if (root->grpno == grpno)
00394     {
00395       fprintf(stderr, "libcheetah: hit at root\n");
00396       return 0;
00397     }
00398   else
00399     {
00400       top = 0;
00401       ptr = root->lft;  /* Starts at root->lft to avoid involving
00402                            root in balance operations */
00403       while (ptr)
00404         {
00405           ++comp;
00406           ++top;
00407           p_stack[top] = ptr;
00408           if ((ptr->grpno < grpno)
00409               || ((ptr->grpno == grpno) && (ptr->prty > prty)))
00410             ptr = ptr->lft;
00411           else
00412             {
00413               if ((ptr->grpno == grpno) && (ptr->prty == prty))
00414                 {
00415                   pos = top;
00416                   break;
00417                 }
00418               ptr = ptr->rt;
00419             }
00420         }
00421 
00422       p_stack[pos]->grpno = ins_entry->grpno;
00423       p_stack[pos]->prty  = ins_entry->prty;
00424       p_stack[pos]->addr = ins_entry->addr;
00425       inserted_node = p_stack[pos];
00426 
00427       at = pos;
00428       while (at > 1)
00429         {
00430           ++no_splay_steps;   /* Counts the number of basic operations */
00431           splay(at, p_stack);
00432           at = at - 2;
00433         }
00434       root->lft = p_stack[1];
00435       return inserted_node;
00436     } /* else */
00437 }
00438 
00439 
00440 /*********************************************************************
00441 Given an entry in the stack returns the previous entry
00442 
00443 Input: Pointer to entry
00444 Output: Pointer to previous entry
00445 Side effects: None
00446 *********************************************************************/
00447 struct tree_node *
00448 Lookup_prev(struct tree_node *entry)
00449 {
00450   struct tree_node *ptr, *lstlft_node;
00451   int grpno, prty;
00452 
00453   grpno = entry->grpno;
00454   prty = entry->prty;
00455   ptr = root;
00456   while (ptr)
00457     {
00458       ++comp;
00459       if ((ptr->grpno < grpno)
00460           || ((ptr->grpno == grpno) && (ptr->prty > prty)))
00461         {
00462           lstlft_node = ptr;
00463           ptr = ptr->lft;
00464         }
00465       else
00466         {
00467           if ((ptr->grpno == grpno) && (ptr->prty == prty))
00468             break;
00469           ptr = ptr->rt;
00470         }
00471     }                                                            
00472 
00473   if ((ptr == NULL) || (ptr->rt == NULL)) 
00474     return lstlft_node;
00475   else
00476     {
00477       ptr = ptr->rt;
00478       while (ptr->lft != NULL)
00479         ptr = ptr->lft;
00480       return ptr;
00481     }
00482 }
00483 
00484 
00485 /*********************************************************************
00486 Given an entry in the stack returns the next entry
00487 
00488 Input: Pointer to entry
00489 Output: Pointer to next entry
00490 Side effects: None
00491 *********************************************************************/
00492 struct tree_node *
00493 Lookup_next(struct tree_node *entry)
00494 {
00495   struct tree_node *ptr, *lstrt_node;
00496   int grpno, prty;
00497 
00498   grpno = entry->grpno;
00499   prty = entry->prty;
00500   ptr = root;
00501   while (ptr)
00502     {
00503       ++comp;
00504       if ((ptr->grpno < grpno)
00505           || ((ptr->grpno == grpno) && (ptr->prty > prty)))
00506         ptr = ptr->lft;
00507       else
00508         {
00509           if ((ptr->grpno == grpno) && (ptr->prty == prty))
00510             break;
00511           lstrt_node = ptr;
00512           ptr = ptr->rt;
00513         }
00514     }                                                            
00515 
00516   if ((ptr == NULL) || (ptr->lft == NULL))
00517     return lstrt_node;
00518   else
00519     {
00520       ptr = ptr->lft;
00521       while (ptr->rt != NULL)
00522         ptr = ptr->rt;
00523       return ptr;
00524     }
00525 }
00526 
00527 
00528 /**************************************************************
00529 Inserts node in the tree
00530 
00531 Input: Node to be inserted
00532 Output: None
00533 Side effects: The node is inserted in its proper position
00534 **************************************************************/
00535 void
00536 Insert_no_Balance(struct tree_node *ins_node)
00537 {
00538   struct tree_node *ptr,            /* Scratch pointers */
00539         *oldptr;
00540   register int grpno,               /* Group no. to be searched */
00541         prty;               /* Priority of entry to be searched */
00542   int lstlft;                      /* Flag for type of last branch */
00543 
00544   ins_node->lft = ins_node->rt = NULL;
00545   if (root == NULL)
00546     root = ins_node;
00547   else
00548     {
00549       grpno = ins_node->grpno;
00550       prty = ins_node->prty;
00551       ptr = root;
00552       while (ptr)
00553         {
00554           oldptr = ptr;
00555           ++comp_ins;
00556           if (ptr->grpno < grpno)
00557             {
00558               ptr = ptr->lft;
00559               lstlft = 1;
00560             }
00561           else if (ptr->grpno == grpno)
00562             {
00563               if (ptr->prty > prty)
00564                 {
00565                   ptr = ptr->lft;
00566                   lstlft = 1;
00567                 }
00568               else if (ptr->prty < prty)
00569                 {
00570                   ptr = ptr->rt;
00571                   lstlft = 0;
00572                 }
00573               else
00574                 {
00575                   fprintf(stderr, "libcheetah: error in insert\n");
00576                   break;
00577                 }
00578             }
00579           else
00580             {
00581               ptr = ptr->rt;
00582               lstlft = 0;
00583             }
00584         }
00585       if (lstlft)
00586         oldptr->lft = ins_node;
00587       else
00588         oldptr->rt = ins_node;
00589     }
00590 }
00591 
00592 
00593 /********************************************************************
00594 Same as above but the inserted node is splayed to the top
00595 
00596 Input: Node to be inserted
00597 Output: None
00598 Side effects: The node is added to the tree and splayed to the top
00599 ********************************************************************/
00600 void
00601 Insert_and_Balance(struct tree_node *ins_node)
00602 {
00603   struct tree_node *ptr,            /* Scratch pointers */
00604         *oldptr;
00605   int lstlft,                      /* Flag for type of last branch */
00606         grpno,                      /* Group no. to be searched */
00607         prty,                       /* Priority of entry to be searched */
00608         top,
00609         at;
00610 
00611   ins_node->lft = ins_node->rt = NULL;
00612   if (root == NULL)
00613     root = ins_node;
00614   else
00615     {
00616       if (root->lft == NULL)
00617         root->lft = ins_node;
00618       else
00619         {
00620           grpno = ins_node->grpno;
00621           prty = ins_node->prty;
00622           ptr = root->lft;
00623           top = 0;
00624           while (ptr)
00625             {
00626               ++top;
00627               p_stack[top] = ptr;
00628               oldptr = ptr;
00629               ++comp_ins;
00630               if ((ptr->grpno < grpno)
00631                   || ((ptr->grpno == grpno) && (ptr->prty > prty)))
00632                 {
00633                   ptr = ptr->lft;
00634                   lstlft = 1;
00635                 }
00636               else
00637                 {
00638                   if ((ptr->grpno == grpno) && (ptr->prty == prty))
00639                     {
00640                       fprintf(stderr, "libcheetah: error in Insert\n");
00641                       break;
00642                     }
00643                   ptr = ptr->rt;
00644                   lstlft = 0;
00645                 }
00646             }
00647           ++top;
00648           p_stack[top] = ins_node;
00649           if (lstlft)
00650             oldptr->lft = ins_node;
00651           else
00652             oldptr->rt = ins_node;
00653 
00654           /* Splay only if path > log(tot_addrs) */
00655           if (top > log_tot_addrs)
00656             {
00657               at = top;
00658               while (at > 1)
00659                 {
00660                   ++no_splay_steps;   /* Count number of basic operations */
00661                   splay(at, p_stack);
00662                   at = at - 2;
00663                 }
00664               root->lft = p_stack[1];
00665             }
00666         }
00667     }
00668 }
00669 
00670 
00671 /******************************************************************
00672 Routine to decide whether to call Insert_no_Balance() or
00673 Insert_and_Balance(). Currently calls the routines alternately.
00674 
00675 Input: Node to be inserted
00676 Output: None
00677 Side effects: Calls an insertion rutine which inserts ins_node
00678 and balances stack if required.
00679 ******************************************************************/
00680 void
00681 Insert(struct tree_node *ins_node)
00682 {
00683   static short insert_flag = 0;
00684 
00685   if (insert_flag)
00686     Insert_and_Balance(ins_node);
00687   else
00688     Insert_no_Balance(ins_node);
00689   toggle(insert_flag);
00690 }
00691 
00692 
00693 /********************************************************************
00694 Deletes node and returns a pointer to the previous node in the stack
00695 
00696 Input: Entry to be deleted
00697 Output: Pointer to entry deleted and
00698         pointer to prev entry (returned using prev_entry
00699 Side effects: An entry is deleted from the stack
00700 ********************************************************************/
00701 struct tree_node *
00702 Delete(struct tree_node *entry, struct tree_node **prev_entry)
00703 {
00704   register int grpno,
00705         prty;
00706   struct tree_node *ptr,     /* Scratch pointers */
00707         *oldptr_dn,
00708         *oldptr_mn,
00709         *dn = NULL,     /* Node deleted */
00710         *mn,    /* Node moved */
00711         *lstlft_node;
00712   int lstlft_dn,                /* Flags indicating type of last branch */
00713         lstlft_mn;
00714 
00715   grpno = entry->grpno;
00716   prty = entry->prty;
00717   ptr = root;
00718   while (ptr)
00719     {
00720       ++comp_del;
00721       if ((ptr->grpno < grpno)
00722           || ((ptr->grpno == grpno ) && (ptr->prty > prty)))
00723         {
00724           oldptr_dn = ptr;
00725           lstlft_node = ptr;
00726           ptr = ptr->lft;
00727           lstlft_dn = 1;
00728         }
00729       else
00730         {
00731           if ((ptr->grpno == grpno) && (ptr->prty == prty))
00732             {
00733               dn = ptr;
00734               break;
00735             }
00736           oldptr_dn = ptr;
00737           ptr = ptr->rt;
00738           lstlft_dn = 0;
00739         }
00740     } /* while */
00741   if (dn == NULL)
00742     {
00743       fprintf(stderr, "libcheetah: error in delete\n");
00744       return (0);
00745     }
00746   else
00747     {
00748       if (ptr->rt == NULL)
00749         {
00750           if (ptr == root)
00751             root = ptr->lft;
00752           else if (lstlft_dn)
00753             oldptr_dn->lft = ptr->lft;
00754           else
00755             oldptr_dn->rt = ptr->lft;
00756           *prev_entry = lstlft_node;
00757         }
00758       else if (ptr->lft == NULL)
00759         {
00760           if (ptr == root)
00761             root = ptr->rt;
00762           else if (lstlft_dn)
00763             oldptr_dn->lft = ptr->rt;
00764           else
00765             oldptr_dn->rt = ptr->rt;
00766           ptr = ptr->rt;
00767           while (ptr->lft != NULL)
00768             ptr = ptr->lft;
00769           *prev_entry = ptr;
00770         }
00771       else
00772         {
00773           oldptr_mn = ptr;
00774           ptr = ptr->rt;
00775           lstlft_mn = 0;
00776           while (ptr->lft != NULL)
00777             {
00778               oldptr_mn = ptr;
00779               ptr = ptr->lft;
00780               lstlft_mn = 1;
00781             }
00782           mn = ptr;
00783           *prev_entry = mn;
00784           if (lstlft_mn)
00785             oldptr_mn->lft = mn->rt;
00786           else
00787             oldptr_mn->rt = mn->rt;
00788           mn->lft = dn->lft;
00789           mn->rt = dn->rt;
00790           if (dn == root)
00791             root = mn;
00792           else if (lstlft_dn)
00793             oldptr_dn->lft = mn;
00794           else
00795             oldptr_dn->rt = mn;
00796         }
00797       return dn;
00798     }
00799 }
00800 
00801 
00802 /**********************************************************
00803   Does the stack processing for each address in the trace for
00804   OPT replacement.
00805 
00806   The stack is maintained as a tree. A list of groups constituting
00807   the stack is maintained. This list is traversed by the procedure.
00808   It calls special tree handling routines to perform some stack operations
00809   and to maintain the group list.
00810 
00811   Input: address referenced and its priority(a fn of its time of next refn)
00812   Output: none
00813   Side effects: Updates the stack depth hit array
00814                 Updates the group list and the tree.
00815 **********************************************************/
00816 int
00817 process_groups(md_addr_t addr,          /* address referenced */
00818                int priority)            /* new priority of address */
00819 {
00820   int depth;            /* Stack depth counter */
00821   struct group_desc *grpptr,            /* Scratch pointer */
00822         *oldgrpptr,
00823         *newgrpptr;
00824   struct tree_node *prev_entry, *grpsecond;
00825   static struct tree_node dummy_for_del_line;
00826   /* One extra node is allocated for del_line which changes */
00827   static struct tree_node *del_line = &dummy_for_del_line;
00828 
00829   /* Hit at top */
00830   if (headgrp.first->addr == addr)
00831     {
00832       ++ out_stack[1];
00833       headgrp.first->prty = priority;
00834       headgrp.first->addr = addr;
00835     }
00836   else
00837     {
00838       /* Depth two hit */
00839       grpptr = headgrp.nxt;
00840       ++grps_passd;
00841 
00842       /* For inf_handler */
00843       if (headgrp.first->prty < 0)
00844         {
00845           /* A kludge to set grptime correctly on a depth two hit */
00846           if (headgrp.nxt->first->addr == addr)
00847             unk_hash_add_fa(headgrp.first->addr,
00848                             (headgrp.nxt->grpno-1), headgrp.first->prty);
00849           else
00850             unk_hash_add_fa(headgrp.first->addr,
00851                             headgrp.nxt->grpno, headgrp.first->prty);
00852         }
00853 
00854       if (grpptr->first->addr == addr)
00855         {
00856           ++out_stack[2];
00857 
00858           if (grpptr->wt == 1)
00859             {
00860               /* One entry in first group */
00861               grpptr->first->addr = headgrp.first->addr;
00862               grpptr->first->prty = headgrp.first->prty;
00863             }
00864           else
00865             {
00866               grpsecond = Lookup_next (grpptr->first);
00867               if (grpsecond->grpno != grpptr->grpno)
00868                 fprintf(stderr, "libcheetah: inconsistent next entry\n");
00869               if (grpsecond->prty < headgrp.first->prty)
00870                 {
00871                   /* Coalescing. new group not needed */
00872                   grpptr->first->addr = headgrp.first->addr;
00873                   grpptr->first->prty = headgrp.first->prty;
00874                 }
00875               else
00876                 {
00877                   --grp_ct;
00878 
00879                   /* A new group is created */
00880                   newgrpptr = calloc(1, sizeof (struct group_desc)) ;
00881                   if (!newgrpptr)
00882                     fatal("out of virtual memory");
00883 
00884                   newgrpptr->first = grpptr->first;
00885                   newgrpptr->last = grpptr->first;
00886                   newgrpptr->grpno = grp_ct;
00887                   newgrpptr->wt = 1;
00888                   newgrpptr->first->addr = headgrp.first->addr;
00889                   newgrpptr->first->prty = headgrp.first->prty;
00890                   newgrpptr->first->grpno = grp_ct;
00891                   newgrpptr->nxt = grpptr;
00892                   headgrp.nxt = newgrpptr;
00893 
00894                   /* adjust next group */
00895                   grpptr->first = grpsecond;
00896                   grpptr->wt -= 1;
00897                 }
00898             }
00899           headgrp.first->addr = addr;
00900           headgrp.first->prty = priority;
00901         }
00902       else
00903         {
00904           /* Hit at second or higher group */
00905           del_line->prty = headgrp.first->prty;
00906           del_line->addr = headgrp.first->addr;
00907           headgrp.first->addr = addr;
00908           headgrp.first->prty = priority;
00909 
00910           if (del_line->prty > grpptr->last->prty)
00911             {
00912               /* del_line enters group. last entry bcomes del_line */
00913               del_line->grpno = grpptr->grpno;
00914               Insert (del_line);
00915               if (del_line->prty > grpptr->first->prty)
00916                 grpptr->first = del_line;
00917               del_line = Delete (grpptr->last, &prev_entry);
00918               grpptr->last = prev_entry;
00919               if (grpptr->last->grpno != grpptr->grpno)
00920                 fprintf(stderr, "libcheetah: inconsistent prev entry\n");
00921             }
00922 
00923           oldgrpptr = grpptr;
00924           depth = grpptr->wt + 1;
00925           grpptr = grpptr->nxt;
00926    
00927           while (grpptr != NULL)
00928             {
00929               ++grps_passd;
00930               if (grpptr->first->addr == addr)
00931                 {
00932                   /* Hit */
00933                   if ((unsigned)(depth+1) <= MAX_LINES)
00934                     ++out_stack[depth+1];
00935 
00936                   del_line->grpno = oldgrpptr->grpno;
00937                   oldgrpptr->last =
00938                     Lookup_Delete_Insert(grpptr->first, del_line);
00939                   oldgrpptr->wt += 1;
00940 
00941                   if (grpptr->first == grpptr->last)
00942                     {
00943                       /* delete group if it had only the refned entry */
00944                       oldgrpptr->nxt = grpptr->nxt;
00945                       free (grpptr);
00946                       grpptr = oldgrpptr; /* grpptr should not be NULL */
00947                     }
00948                   else
00949                     {
00950                       /* else set group-first to next entry */
00951                       grpptr->first  = Lookup_next(grpptr->first);
00952                       grpptr->wt -= 1;
00953                       if (grpptr->first->grpno != grpptr->grpno)
00954                         fprintf(stderr,
00955                                 "libcheetah: inconsistent next entry\n");
00956                     }
00957                   break;
00958                 }
00959               else if (del_line->prty > grpptr->last->prty)
00960                 {
00961                   /* del_line enters group. last entry bcomes del_line */
00962                   del_line->grpno = grpptr->grpno;
00963                   Insert (del_line);
00964                   if (del_line->prty > grpptr->first->prty)
00965                     grpptr->first = del_line;
00966                   del_line = Delete (grpptr->last, &prev_entry);
00967 
00968                   grpptr->last = prev_entry;
00969                   if (grpptr->last->grpno != grpptr->grpno)
00970                     fprintf(stderr, "libcheetah: inconsistent prev entry\n");
00971                 }
00972               oldgrpptr = grpptr;
00973               depth += grpptr->wt;
00974               grpptr = grpptr->nxt;
00975             } /* while */
00976         } /* else */
00977 
00978       if (grpptr == NULL)
00979         {
00980           /* refned address is new (compulsory miss)  */
00981           /* If stack has overflowed, del_line is not added to the end
00982              of the stack. Also, if del_line is an unknown, it is deleted
00983              from the ft_hash_table as well. Unknowns are deleted from
00984              the unknown hash table only during the cleaning step */
00985           if (size_exceeded)
00986             {
00987               if (del_line->prty < 0)
00988                 ft_hash_del(del_line->addr);
00989             }
00990           else
00991             {
00992               del_line->grpno = oldgrpptr->grpno;
00993               Insert(del_line);
00994               oldgrpptr->last = del_line;
00995               oldgrpptr->wt += 1;
00996               del_line = calloc(1, sizeof(struct tree_node));
00997               if (!del_line)
00998                 fatal("out of virtual memory");
00999             }
01000           return 1;
01001         }
01002     } /* else */
01003 
01004   return 0;
01005 }
01006 
01007 
01008 /**********************************************************************
01009 Main simulation routine. Processes the addr_array and time_array obtained
01010 from the pre-processing routine.
01011 
01012 Input: The range in the addr_array (time_array) to be processed
01013 Output: -1 if limit on the addresses to be processed is reached
01014          0 otherwise
01015 Side effects: The stack and group list are updated as the addresses are
01016               preocessed.
01017 **********************************************************************/
01018 int
01019 stack_proc_fa(int start,                /* index of starting array location */
01020               int end)                  /* index of ending array location */
01021 {
01022    int i, l;
01023    unsigned addr;
01024    int priority, new_addrs;
01025    struct tree_node *nnode;
01026 
01027    if (t_entries == 0)
01028      {
01029        root = calloc(1, sizeof(struct tree_node));
01030        if (!root)
01031          fatal("out of virtual memory");
01032 
01033        root->rt = root->lft = NULL;
01034        root->prty = Priority_fa(0);
01035        root->addr = addr_array[0];
01036        root->grpno = 0;
01037 
01038        l = 0;
01039        while ((addr_array[l] == addr_array[0]) && (l < end))
01040          ++l;
01041 
01042        nnode = calloc(1, sizeof(struct tree_node));
01043        if (!nnode)
01044          fatal("out of virtual memory");
01045 
01046        nnode->rt = nnode->lft = NULL;
01047        priority = Priority_fa(l-1);
01048        nnode->prty = priority;
01049        nnode->addr = root->addr;
01050        if (nnode->prty < 0)
01051          unk_hash_add_fa(addr_array[l-1], MAXINT, priority);
01052        nnode->grpno = MAXINT;
01053        priority = Priority_fa(l);
01054        root->prty = priority;
01055        root->addr = addr_array[l];
01056        root->lft = nnode;
01057        headgrp.first = headgrp.last = root;
01058        headgrp.grpno = 0;
01059 
01060        headgrp.nxt = calloc(1, sizeof (struct group_desc));
01061        if (!headgrp.nxt)
01062          fatal("out of virtual memory");
01063 
01064        headgrp.nxt->first = nnode;
01065        headgrp.nxt->last = nnode;
01066        headgrp.nxt->grpno = MAXINT;
01067        headgrp.nxt->wt = 1;
01068        headgrp.nxt->nxt = NULL;
01069 
01070        out_stack[1] += l-1;
01071        tot_addrs = 2;
01072        log_tot_addrs = 1;
01073        next_two_pwr = 4;
01074        for (i=0; i<=l; i++)
01075          {
01076            addr_array[i] = 0;
01077            time_array[i] = 0;
01078          }
01079        start = l+1;
01080        t_entries = l+1;
01081      }
01082 
01083    for (l=start; l<end; l++)
01084      {
01085        ++t_entries;
01086        addr = addr_array[l];
01087        if (t_entries > next_save_time)
01088          {
01089            outpr_facopt(stderr);
01090            next_save_time += SAVE_INTERVAL;
01091          }
01092        if (t_entries > next_clean_time)
01093          {
01094            if (size_exceeded)
01095              hash_clean_fa();
01096            next_clean_time += CLEAN_INTERVAL;
01097          }
01098 
01099        if ((t_entries % P_INTERVAL) == 0)
01100          fprintf(stderr, "libcheetah: addresses processed  %d\n", t_entries);
01101 
01102        priority = Priority_fa(l);
01103 
01104        if ((new_addrs = process_groups(addr, priority)) == 1)
01105          {
01106            ++tot_addrs;
01107            if ((unsigned)tot_addrs > next_two_pwr)
01108              {
01109                ++log_tot_addrs;
01110                next_two_pwr *= 2;
01111              }
01112            if (size_exceeded == 0)
01113              {
01114                if ((unsigned)tot_addrs > MAX_LINES)
01115                  {
01116                    toggle(size_exceeded);
01117                    fprintf(stderr,
01118                            "libcheetah: tot_addrs limit exceeded, "
01119                            "t_entries=%d\n",
01120                            t_entries);
01121                  }
01122              }
01123          }
01124        addr_array[l] = 0;
01125        time_array[l] = 0;
01126        if (t_entries > T)
01127          return 1;
01128      } /* for */
01129 
01130    return 0;
01131 }
01132 
01133 
01134 /*********************************************************************
01135 Initialization routine. Creates a root for the splay tree
01136 and allocates space for the arrays.
01137 
01138 Input: None
01139 Output: None
01140 Side effects: Creates a root for the tree. Adds the address to the splay tree.
01141 *********************************************************************/
01142 void
01143 init_facopt(void)
01144 {
01145   CLEAN_INTERVAL = 10000000;
01146   next_save_time = SAVE_INTERVAL;
01147 
01148   /* Stack is not cut off precisely at MAX_LINES */
01149   out_stack = calloc(MAX_LINES, sizeof (unsigned));
01150   if (!out_stack)
01151     fatal("out of virtual memory");
01152 
01153   p_stack = calloc((MAX_LINES+1000), sizeof (struct tree_node *));
01154   if (!p_stack)
01155     fatal("out of virtual memory");
01156 
01157   next_clean_time = CLEAN_INTERVAL;
01158 }
01159 
01160 
01161 /*********************************************************************
01162 Inorder traversal using a stack.
01163 Adapted from Harry Smith (page 214)
01164 
01165 Starts at the bottom most entry of a group and searches upward for
01166 the first node such that
01167 1. It is that of the referenced address
01168 2. It has a priority less than the del_prty but greater than search_prty.
01169    search_prty is the -ve old prty of the referenced address and the second
01170    second condition ensures that only entries that have interacted with
01171    the referenced address are rearranged.
01172    del_prty is the priority of the address deleted from
01173    the previous group and the first condition ensures that it displaces
01174    only entries of lower priority. For the first group del_prty is set
01175    to 0 which ensures that the entry deleted is of negative priority.
01176 
01177 Input: last entry of group, dummy priority of refned unknown and
01178        dummy priority of deleted unknown
01179 Output: Returns pointer to node matching the above condition
01180 Side effects: None
01181 ************************************************************************/
01182 struct tree_node *
01183 Get_first_unknown(struct tree_node *entry, int search_prty, int del_prty)
01184 {
01185   int grpno, prty, top;
01186   struct tree_node *ptr;
01187 
01188   grpno = entry->grpno;
01189   prty = entry->prty;
01190   ptr = root;
01191   top = 0;
01192   while (ptr)
01193     {
01194       if ((ptr->grpno < grpno)
01195           || ((ptr->grpno == grpno) && (ptr->prty > prty)))
01196         {
01197           ++top;
01198           p_stack[top] = ptr;
01199           ptr = ptr->lft;
01200         }
01201       else
01202         {
01203           if ((ptr->grpno == grpno) && (ptr->prty == prty))
01204             {
01205               ++top;
01206               p_stack[top] = ptr;
01207               break;
01208             }
01209           ptr = ptr->rt;
01210         }
01211     }
01212 
01213   while (top > 0)
01214     {
01215       ptr = p_stack[top];
01216       --top;
01217       /* visit node */
01218       /* printf("%d  %d   %d\n", ptr->addr, ptr->grpno, ptr->prty); */
01219       if ((ptr->prty > 0) || (ptr->grpno != grpno))
01220         return NULL;
01221       else if ((ptr->prty == search_prty)
01222                || ((ptr->prty < del_prty) && (ptr->prty > search_prty)))
01223         return ptr;
01224 
01225       ptr = ptr->rt;
01226       while (ptr)
01227         {
01228           ++top;
01229           p_stack[top] = ptr;
01230           ptr = ptr->lft;
01231         }
01232     }
01233 
01234   /* should not get here... */
01235   return NULL;
01236 }
01237 
01238 
01239 /*********************************************************************
01240 Given an entry in the stack returns the previous entry
01241 
01242 Input: Pointer to entry
01243 Output: Pointer to previous entry
01244 Side effects: None
01245 *********************************************************************/
01246 
01247 struct tree_node *
01248 Get_first_unknown_wobacking(int grpno, int search_prty, int del_prty)
01249 {
01250   struct tree_node *ptr, *lstlft_node;
01251 
01252   ptr = root;
01253   while (ptr)
01254     {
01255       ++comp;
01256       if ((ptr->grpno < grpno)
01257           || ((ptr->grpno == grpno) && (ptr->prty > search_prty)))
01258         {
01259           lstlft_node = ptr;
01260           ptr = ptr->lft;
01261         }
01262       else
01263         {
01264           if ((ptr->grpno == grpno) && (ptr->prty == search_prty))
01265             return ptr;
01266           ptr = ptr->rt;
01267         }
01268     }                                                            
01269 
01270   if ((lstlft_node->grpno == grpno) && (lstlft_node->prty < del_prty))
01271     return lstlft_node;
01272   else
01273     return NULL;
01274 }        
01275 
01276 
01277 /********************************************************************
01278 When an unknown is referenced this routine moves it to its right position
01279 in the stack and rearranges the other unknowns as required
01280 
01281 Input: Address and the current time of the pre-processing routine
01282 Output: None
01283 Side effects: The stack is rearranged and the group list is updated
01284               if required.
01285 *********************************************************************/
01286 void
01287 inf_handler_fa(md_addr_t addr, int cur_time)
01288 {
01289   struct tree_node *line_to_be_ins, /* scratch pointers */
01290         *line_to_be_del,
01291         *prev_entry;
01292   struct group_desc *grpptr;    /* scratch */
01293   int addr_grptime,             /* group time marker for unknown */
01294         addr_prty;
01295   int priority, /* fn of cur_time */
01296         del_prty;       /* prty of deleted entry (during rearrangement) */
01297   static struct tree_node dummy_for_del_line;
01298   /* One extra node is allocated for del_line which changes */
01299   static struct tree_node *del_line = &dummy_for_del_line;
01300 
01301   ++ihcount;
01302 
01303   priority = MAXINT - cur_time; /* assumes a priority function */
01304 
01305   if ((headgrp.first != NULL) && (headgrp.first->addr == addr))
01306     {
01307       if (headgrp.first->prty > 0)
01308         fprintf(stderr, "libcheetah: unknown has > 0 prty\n");
01309       else
01310         headgrp.first->prty = priority;
01311       return;
01312     }
01313 
01314   addr_grptime = unk_hash_del_fa (addr, &addr_prty);
01315   if (addr_grptime == 0)
01316     return;
01317 
01318   --unknowns;
01319 
01320   grpptr = headgrp.nxt; /* assumed that a unknown is not fixed
01321                            when it is at the top */
01322 
01323   /*printf ("inf_handler addr: %d %d\n", addr, addr_grptime);
01324     traverse(root);*/
01325 
01326   while (grpptr)
01327     {
01328       if (grpptr->grpno < addr_grptime)
01329         grpptr = grpptr->nxt;
01330       else
01331         break;
01332     }
01333 
01334   /* if (grpptr == NULL)
01335      printf ("Error in inf_handler: addr_grptime not found\n"); */
01336 
01337   while (grpptr)
01338     {
01339       if (grpptr->last->prty > 0)
01340         grpptr  = grpptr->nxt;
01341       else
01342         break;
01343     }
01344 
01345   /* if (grpptr == NULL)
01346      printf ("Error in inf_handler: no unknowns found\n"); */
01347 
01348   line_to_be_ins = del_line;
01349   line_to_be_ins->prty = priority;
01350   line_to_be_ins->addr = addr;
01351 
01352   del_prty = 0;
01353   while (grpptr)
01354     {
01355       line_to_be_del =
01356         Get_first_unknown_wobacking (grpptr->grpno, addr_prty, del_prty);
01357       if (line_to_be_del != NULL)
01358         {
01359           line_to_be_ins->grpno = grpptr->grpno;
01360           Insert(line_to_be_ins);
01361           if (line_to_be_ins->prty > grpptr->first->prty)
01362             grpptr->first = line_to_be_ins;
01363           line_to_be_ins = Delete(line_to_be_del, &prev_entry);
01364           if (grpptr->last == line_to_be_del)
01365             grpptr->last = prev_entry;
01366           if (line_to_be_del->prty == addr_prty)
01367             break;
01368           del_prty = line_to_be_ins->prty;
01369         }
01370       grpptr = grpptr->nxt;
01371     }
01372   del_line = line_to_be_ins;
01373 
01374   /* if (grpptr == NULL)
01375      printf ("Error in inf_handler: unknown not found\n"); */
01376 }


UVa CS Department of Computer Science
School of Engineering, University of Virginia
151 Engineer's Way, P.O. Box 400740
Charlottesville, Virginia 22904-4740

(434) 982-2200  Fax: (434) 982-2214