| Profiler |

    1   /*
    2    *  Profiler.java - A simple profiling utility
    3    *
    4    *  Copyright (c) 2001, OntoText Lab. (http://www.ontotext.com)
    5    *
    6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
    7    *  software, licenced under the GNU Library General Public License,
    8    *  Version 2, June 1991 (in the distribution as file licence.html,
    9    *  and also available at http://gate.ac.uk/gate/licence.html).
    10   *
    11   *  Atanas Kiryakov, 05/11/01
    12   *
    13   *  $Id: Profiler.java,v 1.1 2001/11/05 16:11:24 nasso Exp $
    14   */
    15
    16
    17  package gate.util.profile;
    18
    19  /**
    20   *  This is a simple "code-internal" profiler which can be used
    21   *  by introducing calls to its methods (mostly, checkPoint()) in  the code.
    22   *  It allows detection and reporting of time and memory usage
    23   *  between execution points as well as for the whole run. In addition allows
    24   *  for collection/reporting of the resources usage by categories (types of
    25   *  activity performed between the check point and the previous one).
    26   *  The results are currently just dumped to the output.
    27   *  <p>
    28   *  Important feature is the possibility of the memory usage measurment code
    29   *  to call the Garbage Collector following a specific strategy that allows
    30   *  the real memory usage to be deteceted. This feature can be switched OFF
    31   *  if appropriate, for example, if the *real* run-time memory usage have to
    32   *  be measured rather than the precise but ideallistic one provided otherwise.
    33   *  <p>
    34   *  The profiler can be switched OFF using the enable(boolean) method. In such
    35   *  case it ignores any calls to its checkPoint(...) method, so, basically does
    36   *  nothing. This feature is usefull in cases when the profiler have to be
    37   *  "stripped" from the code in order to allow non-disturbed execution.
    38   *  <p>
    39   *  The profiler takes care to calculate the time exlusive its footprint. It
    40   *  takes account for both "net" time and the absolute duration. Also in
    41   *  relation to the execution time measurment - it depends on the speed of the
    42   *  machine as well as on the other applications running in parallel.
    43   */
    44
    45  import java.io.*;
    46  import java.util.*;
    47
    48  public class Profiler {
    49
    50    private PrintStream m_out;
    51    private boolean m_enabled = true;
    52    private boolean m_garbageCollection = true;
    53
    54    // keeps the sum of the time spend on a category of tasks
    55    // the catoegries are identified via strings which are used as
    56    // keys in the table. The values in the table are Long objects, millisec.
    57    private Hashtable m_categorySums;
    58
    59    // keeps the time spend on the last task of a category
    60    // the catoegries are identified via strings which are used as
    61    // keys in the table. The values in the table are Long objects, millisec.
    62    private Hashtable m_categoryLasts;
    63
    64    private Runtime m_rt;
    65
    66    // all the time constants below in 1/1000s
    67    // the time when the profiler was intiated for the current run
    68    private long m_startTime;
    69    private long m_lastCheckTime, m_profilerTime, m_lastDuration;
    70
    71    private long m_maxMemory, m_currMemory, m_diffMemory;
    72
    73    public Profiler() {
    74      m_rt = Runtime.getRuntime();
    75      m_out = System.out;
    76    }
    77
    78    /**
    79     * Switches the profiler ON and OFF. When OFF all the methods do nothing
    80     */
    81    public void enable(boolean isEnabled) {
    82      m_enabled = isEnabled;
    83    } // enable
    84
    85    /**
    86     * Answers is the profiler switched ON or OFF. When OFF all the methods do
    87     * nothing
    88     */
    89    public boolean isEnabled() {
    90      return m_enabled;
    91    }
    92
    93    /**
    94     * Tell's the profiler whether to call the garbage collector when detecting
    95     * memory usage or not. If switched ON the GC is called following a
    96     * specific strategy as many time as needed so to collect all the memory
    97     * that can be collected. This makes the profiling slower and also does not
    98     * correctly account for the really memory usage of the applicaton when
    99     * run without the profiler. On the other hand, with garbage collection, it
    100    * is easier to detecet the amount of memory really necessary for the
    101    * application.
    102    */
    103   public void enableGCCalling(boolean collect) {
    104     m_garbageCollection = collect;
    105   }
    106
    107   /**
    108    * @see enableGCCalling(boolean)
    109    */
    110   public boolean isGCCallingEnabled() {
    111     return m_garbageCollection;
    112   }
    113
    114
    115   /**
    116    * Returns the time spend by the profiler during the last run. It is the
    117    * case that
    118    *      net_run_time = run_duration - profiler_time
    119    */
    120   public long getProfilerTime() {
    121     return m_profilerTime;
    122   }
    123
    124   /**
    125    * Returns the time spend in the last run without the time
    126    * spend by the profiler. It is the case that
    127    *      net_run_time = run_duration - profiler_time
    128    */
    129   public long getNetRunTime() {
    130     return m_lastCheckTime - m_profilerTime;
    131   };
    132
    133   /**
    134    * Returns the time spend in the current run until the last check-point
    135    * inclusive the time spend by the profiler. It is the case that
    136    *      net_run_time = run_duration - profiler_time
    137    */
    138   public long getRunDuration() {
    139     return m_lastCheckTime;
    140 //        long auxTime1 = (System.currentTimeMillis() - m_startTime1000)/10;
    141 //        return ((double)auxTime1)/100;
    142   } ;
    143
    144
    145   /**
    146    * Inialises the profiler for a new run
    147    */
    148   public void initRun(String runDescription) {
    149     m_out.println("-----------------------------------------------");
    150     m_out.println("New profiler run: " + runDescription);
    151     m_out.println("-----------------------------------------------");
    152
    153     m_maxMemory=0;
    154     m_currMemory=0;
    155     m_diffMemory=0;
    156     m_profilerTime=0;
    157     m_startTime = System.currentTimeMillis();
    158     m_lastCheckTime=0;
    159     m_lastDuration=0;
    160
    161     m_categorySums = new Hashtable();
    162     m_categoryLasts = new Hashtable();
    163   } // initRun
    164
    165   /**
    166    * To be called at all execution points of interest. Detects the time
    167    * and memory usage in absolute terms as well as compared to the previous
    168    * execution point
    169    */
    170   public void checkPoint(String execPointDescr) {
    171     checkPoint(execPointDescr, new String[0], true, true, true);
    172   }
    173
    174   /**
    175    * In addition to the variant of the method with two parameters allows:
    176    * a set of categories (identified by strings) to which the preceeding
    177    * fragment of code belongs; flag determining whether the description of
    178    * the execution point to be displayed; flag determining whether the
    179    * statistics to be shown
    180    */
    181   public void checkPoint(String execPointDescr, String categories[],
    182       boolean showDescr, boolean showStats, boolean memoryCheck)
    183   {
    184     if (!m_enabled)
    185       return;
    186
    187     long currTime = System.currentTimeMillis() - m_startTime;
    188     m_lastDuration = currTime - m_lastCheckTime;
    189
    190     if (memoryCheck) {
    191       long oldMemory = m_currMemory;
    192
    193       if (m_garbageCollection) {
    194         do {
    195           m_currMemory = m_rt.totalMemory() - m_rt.freeMemory();
    196           m_rt.gc();
    197           try {wait(300);} catch (Exception e) {}
    198           m_rt.gc();
    199         } while (m_currMemory > m_rt.totalMemory() - m_rt.freeMemory());
    200       }
    201       else {
    202         m_currMemory = m_rt.totalMemory() - m_rt.freeMemory();
    203       }
    204
    205       m_currMemory /= 1000;
    206       m_maxMemory = Math.max(m_maxMemory, m_currMemory);
    207       m_diffMemory = m_currMemory - oldMemory;
    208     } // if (memoryCheck)
    209
    210     m_lastCheckTime = System.currentTimeMillis() - m_startTime;
    211     m_profilerTime += (m_lastCheckTime - currTime);
    212
    213     checkCategories(categories);
    214     showResults(execPointDescr, showDescr, showStats);
    215   } // checkPoint
    216
    217   private void checkCategories(String categs[]) {
    218     int size = categs.length;
    219     String categ;
    220     long last, sum;
    221     Long l;
    222     for (int i=0; i<size; i++) {
    223       categ = categs[i].toUpperCase();
    224       l = (Long)m_categorySums.get(categ);
    225       sum = (l==null) ? 0 : l.longValue();
    226       sum += m_lastDuration;
    227       m_categorySums.put(categ, new Long(sum));
    228       m_categoryLasts.put(categ, new Long(m_lastDuration));
    229     } // for
    230   } // checkCategories
    231
    232   private void showResults(String execPointDescr, boolean showDescr,
    233       boolean showStats)
    234   {
    235     StringBuffer buff = new StringBuffer(500);
    236     if (showDescr) {
    237       buff.append("---------LOG: ");
    238       buff.append(execPointDescr);
    239       buff.append("---------");
    240     }
    241
    242     if (showStats) {
    243       buff.append("\nMemory: ");
    244       buff.append(m_currMemory);
    245       buff.append("k; change: ");
    246       buff.append(m_diffMemory);
    247       buff.append("k; max: ");
    248       buff.append(m_maxMemory);
    249       buff.append("k; Net time:   ");
    250       buff.append(printTime(getNetRunTime()));
    251       buff.append("; since prev.: ");
    252       buff.append(printTime(m_lastDuration));
    253 //            buff.append("; profiler time: ");
    254 //            buff.append(printTime(m_profilerTime));
    255 //            buff.append("; duration: ");
    256 //            buff.append(printTime(m_lastCheckTime));
    257     }
    258
    259     if (buff.length() > 0) {
    260         m_out.println(buff.toString());
    261     }
    262   } // showResults
    263
    264   /**
    265    * Returns 0 if the category was not found
    266    */
    267   public long getCategoryTimeSum(String category) {
    268     Long sum = (Long)m_categorySums.get(category.toUpperCase());
    269     return (sum == null) ? 0 : sum.longValue();
    270   } // getCategoryTimeSum
    271
    272   /**
    273    * Returns 0 if the category was not found
    274    */
    275   public long getCategoryTimeLast(String category) {
    276     Long sum = (Long)m_categoryLasts.get(category.toUpperCase());
    277     return (sum == null) ? 0 : sum.longValue();
    278   } // getCategoryTimeSum
    279
    280   /**
    281    * Prints the time for all the categories of activities
    282    */
    283   public void showCategoryTimes() {
    284     m_out.println("Time spent by categories:");
    285     Enumeration categNames = m_categorySums.keys();
    286     String categ;
    287     while (categNames.hasMoreElements()) {
    288       categ = (String)categNames.nextElement();
    289       showCategoryTime(categ);
    290     } // while
    291   } // showCategoryTimes
    292
    293   /**
    294    * Prints the time for certain category of activities
    295    */
    296   public void showCategoryTime(String categ) {
    297     m_out.println(categ + ", sum=" +
    298             printTime(getCategoryTimeSum(categ)) +
    299             ", last=" + printTime(getCategoryTimeLast(categ)));
    300   } // showCategoryTimes
    301
    302   /**
    303    * An auxiliary routine printing time in "nnn.nns" format
    304    */
    305   public String printTime(long timeMillis) {
    306     long round = timeMillis/1000;
    307     long remaind = (timeMillis % 1000)/10;
    308     StringBuffer buff = new StringBuffer(10);
    309     buff.append(round);
    310     buff.append(".");
    311     buff.append(remaind);
    312     buff.append("s");
    313     return buff.toString();
    314   } // printTime
    315
    316   /**
    317    * An auxiliary routine printing in a string speed
    318    */
    319   public String printSpeed(long timeMillis,
    320       double whatever, String whateverMeasure)
    321   {
    322     double speed1000 = (double) whatever/ timeMillis;
    323     long round = (long)((double)speed1000*1000);
    324     long remaind =  (long)(((double)speed1000*100000) - 100 * round);
    325     StringBuffer buff = new StringBuffer(10);
    326     buff.append(round);
    327     buff.append(".");
    328     buff.append(remaind);
    329     buff.append(whateverMeasure);
    330     buff.append("/s");
    331     return buff.toString();
    332   } // printTime
    333
    334   /**
    335    * An auxiliary routine printing time, avg. time, and avg. speed for
    336    * a category
    337    */
    338   public void printCategAvg(String categ, long items,
    339       double volume, String whateverMeasure)
    340   {
    341     long time = getCategoryTimeSum(categ);
    342     if (time==0) {
    343       m_out.println("Category \"" + categ + "\" not found");
    344     }
    345
    346     m_out.println("Category \"" + categ + "\",  Time= " +
    347         printTime(time) + "; avg. time= " +
    348         printTime(time/items) +  "; speed= " +
    349         printSpeed(time, volume, whateverMeasure));
    350   } // printCategAvg
    351
    352 } // Profiler

| Profiler |