1 /*
   2  * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.jvmstat.perfdata.monitor.v1_0;
  27 
  28 import sun.jvmstat.monitor.*;
  29 import sun.jvmstat.perfdata.monitor.*;
  30 import java.util.*;
  31 import java.util.regex.*;
  32 import java.nio.*;
  33 
  34 /**
  35  * The concrete implementation of version 1.0 of the HotSpot PerfData
  36  * Instrumentation buffer. This class is responsible for parsing the
  37  * instrumentation memory and constructing the necessary objects to
  38  * represent and access the instrumentation objects contained in the
  39  * memory buffer.
  40  *
  41  * @author Brian Doherty
  42  * @since 1.5
  43  * @see AbstractPerfDataBuffer
  44  */
  45 public class PerfDataBuffer extends PerfDataBufferImpl {
  46 
  47     private static final boolean DEBUG = false;
  48     private static final int syncWaitMs =
  49             Integer.getInteger("sun.jvmstat.perdata.syncWaitMs", 5000);
  50     private static final ArrayList EMPTY_LIST = new ArrayList(0);
  51 
  52     /*
  53      * the following constants must be kept in sync with struct
  54      * PerfDataEntry in perfMemory.hpp
  55      */
  56     private final static int PERFDATA_ENTRYLENGTH_OFFSET=0;
  57     private final static int PERFDATA_ENTRYLENGTH_SIZE=4;   // sizeof(int)
  58     private final static int PERFDATA_NAMELENGTH_OFFSET=4;
  59     private final static int PERFDATA_NAMELENGTH_SIZE=4;    // sizeof(int)
  60     private final static int PERFDATA_VECTORLENGTH_OFFSET=8;
  61     private final static int PERFDATA_VECTORLENGTH_SIZE=4;  // sizeof(int)
  62     private final static int PERFDATA_DATATYPE_OFFSET=12;
  63     private final static int PERFDATA_DATATYPE_SIZE=1;      // sizeof(byte)
  64     private final static int PERFDATA_FLAGS_OFFSET=13;
  65     private final static int PERFDATA_FLAGS_SIZE=1;        // sizeof(byte)
  66     private final static int PERFDATA_DATAUNITS_OFFSET=14;
  67     private final static int PERFDATA_DATAUNITS_SIZE=1;     // sizeof(byte)
  68     private final static int PERFDATA_DATAATTR_OFFSET=15;
  69     private final static int PERFDATA_DATAATTR_SIZE=1;      // sizeof(byte)
  70     private final static int PERFDATA_NAME_OFFSET=16;
  71 
  72     PerfDataBufferPrologue prologue;
  73     int nextEntry;
  74     int pollForEntry;
  75     int perfDataItem;
  76     long lastModificationTime;
  77     int lastUsed;
  78     IntegerMonitor overflow;
  79     ArrayList<Monitor> insertedMonitors;
  80 
  81     /**
  82      * Construct a PerfDataBufferImpl instance.
  83      * <p>
  84      * This class is dynamically loaded by
  85      * {@link AbstractPerfDataBuffer#createPerfDataBuffer}, and this
  86      * constructor is called to instantiate the instance.
  87      *
  88      * @param buffer the buffer containing the instrumentation data
  89      * @param lvmid the Local Java Virtual Machine Identifier for this
  90      *              instrumentation buffer.
  91      */
  92     public PerfDataBuffer(ByteBuffer buffer, int lvmid)
  93            throws MonitorException {
  94         super(buffer, lvmid);
  95         prologue = new PerfDataBufferPrologue(buffer);
  96         this.buffer.order(prologue.getByteOrder());
  97     }
  98 
  99     /**
 100      * {@inheritDoc}
 101      */
 102     protected void buildMonitorMap(Map<String, Monitor> map) throws MonitorException {
 103         assert Thread.holdsLock(this);
 104 
 105         // start at the beginning of the buffer
 106         buffer.rewind();
 107 
 108         // create pseudo monitors
 109         buildPseudoMonitors(map);
 110 
 111         // position buffer to start of the data section
 112         buffer.position(prologue.getSize());
 113         nextEntry = buffer.position();
 114         perfDataItem = 0;
 115 
 116         int used = prologue.getUsed();
 117         long modificationTime = prologue.getModificationTimeStamp();
 118 
 119         Monitor m = getNextMonitorEntry();
 120         while (m != null) {
 121             map.put(m.getName(), m);
 122             m = getNextMonitorEntry();
 123         }
 124 
 125         /*
 126          * set the last modification data. These are set to the values
 127          * recorded before parsing the data structure. This allows the
 128          * the data structure to be modified while the Map is being built.
 129          * The Map may contain more entries than indicated based on the
 130          * time stamp, but this is handled by ignoring duplicate entries
 131          * when the Map is updated in getNewMonitors().
 132          */
 133         lastUsed = used;
 134         lastModificationTime = modificationTime;
 135 
 136         // synchronize with the target jvm
 137         synchWithTarget(map);
 138 
 139         // work around 1.4.2 counter inititization bugs
 140         kludge(map);
 141 
 142         insertedMonitors = new ArrayList<Monitor>(map.values());
 143     }
 144 
 145     /**
 146      * {@inheritDoc}
 147      */
 148     protected void getNewMonitors(Map<String, Monitor> map) throws MonitorException {
 149         assert Thread.holdsLock(this);
 150 
 151         int used = prologue.getUsed();
 152         long modificationTime = prologue.getModificationTimeStamp();
 153 
 154         if ((used > lastUsed) || (lastModificationTime > modificationTime)) {
 155 
 156             lastUsed = used;
 157             lastModificationTime = modificationTime;
 158 
 159             Monitor monitor = getNextMonitorEntry();
 160             while (monitor != null) {
 161                 String name = monitor.getName();
 162 
 163                 // guard against duplicate entries
 164                 if (!map.containsKey(name)) {
 165                     map.put(name, monitor);
 166 
 167                     /*
 168                      * insertedMonitors is null when called from pollFor()
 169                      * via buildMonitorMap(). Since we update insertedMonitors
 170                      * at the end of buildMonitorMap(), it's ok to skip the
 171                      * add here.
 172                      */
 173                     if (insertedMonitors != null) {
 174                         insertedMonitors.add(monitor);
 175                     }
 176                 }
 177                 monitor = getNextMonitorEntry();
 178             }
 179         }
 180     }
 181 
 182     /**
 183      * {@inheritDoc}
 184      */
 185     protected MonitorStatus getMonitorStatus(Map<String, Monitor> map) throws MonitorException {
 186         assert Thread.holdsLock(this);
 187         assert insertedMonitors != null;
 188 
 189         // load any new monitors
 190         getNewMonitors(map);
 191 
 192         // current implementation doesn't support deletion or reuse of entries
 193         ArrayList removed = EMPTY_LIST;
 194         ArrayList inserted = insertedMonitors;
 195 
 196         insertedMonitors = new ArrayList<Monitor>();
 197         return new MonitorStatus(inserted, removed);
 198     }
 199 
 200     /**
 201      * Build the pseudo monitors used to map the prolog data into counters.
 202      */
 203     protected void buildPseudoMonitors(Map<String, Monitor> map) {
 204         Monitor monitor = null;
 205         String name = null;
 206         IntBuffer ib = null;
 207 
 208         name = PerfDataBufferPrologue.PERFDATA_MAJOR_NAME;
 209         ib = prologue.majorVersionBuffer();
 210         monitor = new PerfIntegerMonitor(name, Units.NONE,
 211                                          Variability.CONSTANT, false, ib);
 212         map.put(name, monitor);
 213 
 214         name = PerfDataBufferPrologue.PERFDATA_MINOR_NAME;
 215         ib = prologue.minorVersionBuffer();
 216         monitor = new PerfIntegerMonitor(name, Units.NONE,
 217                                          Variability.CONSTANT, false, ib);
 218         map.put(name, monitor);
 219 
 220         name = PerfDataBufferPrologue.PERFDATA_BUFFER_SIZE_NAME;
 221         ib = prologue.sizeBuffer();
 222         monitor = new PerfIntegerMonitor(name, Units.BYTES,
 223                                          Variability.MONOTONIC, false, ib);
 224         map.put(name, monitor);
 225 
 226         name = PerfDataBufferPrologue.PERFDATA_BUFFER_USED_NAME;
 227         ib = prologue.usedBuffer();
 228         monitor = new PerfIntegerMonitor(name, Units.BYTES,
 229                                          Variability.MONOTONIC, false, ib);
 230         map.put(name, monitor);
 231 
 232         name = PerfDataBufferPrologue.PERFDATA_OVERFLOW_NAME;
 233         ib = prologue.overflowBuffer();
 234         monitor = new PerfIntegerMonitor(name, Units.BYTES,
 235                                          Variability.MONOTONIC, false, ib);
 236         map.put(name, monitor);
 237         this.overflow = (IntegerMonitor)monitor;
 238 
 239         name = PerfDataBufferPrologue.PERFDATA_MODTIMESTAMP_NAME;
 240         LongBuffer lb = prologue.modificationTimeStampBuffer();
 241         monitor = new PerfLongMonitor(name, Units.TICKS,
 242                                       Variability.MONOTONIC, false, lb);
 243         map.put(name, monitor);
 244     }
 245 
 246     /**
 247      * Method to provide a gross level of synchronization with the
 248      * target monitored jvm.
 249      *
 250      * gross synchronization works by polling for the hotspot.rt.hrt.ticks
 251      * counter, which is the last counter created by the StatSampler
 252      * initialization code. The counter is updated when the watcher thread
 253      * starts scheduling tasks, which is the last thing done in vm
 254      * initialization.
 255      */
 256     protected void synchWithTarget(Map<String, Monitor> map) throws MonitorException {
 257         /*
 258          * synch must happen with syncWaitMs from now. Default is 5 seconds,
 259          * which is reasonabally generous and should provide for extreme
 260          * situations like startup delays due to allocation of large ISM heaps.
 261          */
 262         long timeLimit = System.currentTimeMillis() + syncWaitMs;
 263 
 264         String name = "hotspot.rt.hrt.ticks";
 265         LongMonitor ticks = (LongMonitor)pollFor(map, name, timeLimit);
 266 
 267         /*
 268          * loop waiting for the ticks counter to be non zero. This is
 269          * an indication that the jvm is initialized.
 270          */
 271         log("synchWithTarget: " + lvmid + " ");
 272         while (ticks.longValue() == 0) {
 273             log(".");
 274 
 275             try { Thread.sleep(20); } catch (InterruptedException e) { }
 276 
 277             if (System.currentTimeMillis() > timeLimit) {
 278                 lognl("failed: " + lvmid);
 279                 throw new MonitorException("Could Not Synchronize with target");
 280             }
 281         }
 282         lognl("success: " + lvmid);
 283     }
 284 
 285     /**
 286      * Method to poll the instrumentation memory for a counter with
 287      * the given name. The polling period is bounded by the timeLimit
 288      * argument.
 289      */
 290     protected Monitor pollFor(Map<String, Monitor> map, String name, long timeLimit)
 291                       throws MonitorException {
 292         Monitor monitor = null;
 293 
 294         log("polling for: " + lvmid + "," + name + " ");
 295 
 296         pollForEntry = nextEntry;
 297         while ((monitor = map.get(name)) == null) {
 298             log(".");
 299 
 300             try { Thread.sleep(20); } catch (InterruptedException e) { }
 301 
 302             long t = System.currentTimeMillis();
 303             if ((t > timeLimit) || (overflow.intValue() > 0)) {
 304                 lognl("failed: " + lvmid + "," + name);
 305                 dumpAll(map, lvmid);
 306                 throw new MonitorException("Could not find expected counter");
 307             }
 308 
 309             getNewMonitors(map);
 310         }
 311         lognl("success: " + lvmid + "," + name);
 312         return monitor;
 313     }
 314 
 315     /**
 316      * method to make adjustments for known counter problems. This
 317      * method depends on the availability of certain counters, which
 318      * is generally guaranteed by the synchWithTarget() method.
 319      */
 320     protected void kludge(Map<String, Monitor> map) {
 321         if (Boolean.getBoolean("sun.jvmstat.perfdata.disableKludge")) {
 322             // bypass all kludges
 323             return;
 324         }
 325 
 326         String name = "java.vm.version";
 327         StringMonitor jvm_version = (StringMonitor)map.get(name);
 328         if (jvm_version == null) {
 329             jvm_version = (StringMonitor)findByAlias(name);
 330         }
 331 
 332         name = "java.vm.name";
 333         StringMonitor jvm_name = (StringMonitor)map.get(name);
 334         if (jvm_name == null) {
 335             jvm_name = (StringMonitor)findByAlias(name);
 336         }
 337 
 338         name = "hotspot.vm.args";
 339         StringMonitor args = (StringMonitor)map.get(name);
 340         if (args == null) {
 341             args = (StringMonitor)findByAlias(name);
 342         }
 343 
 344         assert ((jvm_name != null) && (jvm_version != null) && (args != null));
 345 
 346         if (jvm_name.stringValue().indexOf("HotSpot") >= 0) {
 347             if (jvm_version.stringValue().startsWith("1.4.2")) {
 348                 kludgeMantis(map, args);
 349             }
 350         }
 351     }
 352 
 353     /**
 354      * method to repair the 1.4.2 parallel scavenge counters that are
 355      * incorrectly initialized by the JVM when UseAdaptiveSizePolicy
 356      * is set. This bug couldn't be fixed for 1.4.2 FCS due to putback
 357      * restrictions.
 358      */
 359     private void kludgeMantis(Map<String, Monitor> map, StringMonitor args) {
 360         /*
 361          * the HotSpot 1.4.2 JVM with the +UseParallelGC option along
 362          * with its default +UseAdaptiveSizePolicy option has a bug with
 363          * the initialization of the sizes of the eden and survivor spaces.
 364          * See bugid 4890736.
 365          *
 366          * note - use explicit 1.4.2 counter names here - don't update
 367          * to latest counter names or attempt to find aliases.
 368          */
 369 
 370         String cname = "hotspot.gc.collector.0.name";
 371         StringMonitor collector = (StringMonitor)map.get(cname);
 372 
 373         if (collector.stringValue().compareTo("PSScavenge") == 0) {
 374             boolean adaptiveSizePolicy = true;
 375 
 376             /*
 377              * HotSpot processes the -XX:Flags/.hotspotrc arguments prior to
 378              * processing the command line arguments. This allows the command
 379              * line arguments to override any defaults set in .hotspotrc
 380              */
 381             cname = "hotspot.vm.flags";
 382             StringMonitor flags = (StringMonitor)map.get(cname);
 383             String allArgs = flags.stringValue() + " " + args.stringValue();
 384 
 385             /*
 386              * ignore the -XX: prefix as it only applies to the arguments
 387              * passed from the command line (i.e. the invocation api).
 388              * arguments passed through .hotspotrc omit the -XX: prefix.
 389              */
 390             int ahi = allArgs.lastIndexOf("+AggressiveHeap");
 391             int aspi = allArgs.lastIndexOf("-UseAdaptiveSizePolicy");
 392 
 393             if (ahi != -1) {
 394                 /*
 395                  * +AggressiveHeap was set, check if -UseAdaptiveSizePolicy
 396                  * is set after +AggressiveHeap.
 397                  */
 398                 //
 399                 if ((aspi != -1) && (aspi > ahi)) {
 400                     adaptiveSizePolicy = false;
 401                 }
 402             } else {
 403                 /*
 404                  * +AggressiveHeap not set, must be +UseParallelGC. The
 405                  * relative position of -UseAdaptiveSizePolicy is not
 406                  * important in this case, as it will override the
 407                  * UseParallelGC default (+UseAdaptiveSizePolicy) if it
 408                  * appears anywhere in the JVM arguments.
 409                  */
 410                 if (aspi != -1) {
 411                     adaptiveSizePolicy = false;
 412                 }
 413             }
 414 
 415             if (adaptiveSizePolicy) {
 416                 // adjust the buggy AdaptiveSizePolicy size counters.
 417 
 418                 // first remove the real counters.
 419                 String eden_size = "hotspot.gc.generation.0.space.0.size";
 420                 String s0_size = "hotspot.gc.generation.0.space.1.size";
 421                 String s1_size = "hotspot.gc.generation.0.space.2.size";
 422                 map.remove(eden_size);
 423                 map.remove(s0_size);
 424                 map.remove(s1_size);
 425 
 426                 // get the maximum new generation size
 427                 String new_max_name = "hotspot.gc.generation.0.capacity.max";
 428                 LongMonitor new_max = (LongMonitor)map.get(new_max_name);
 429 
 430                 /*
 431                  * replace the real counters with pseudo counters that are
 432                  * initialized to to the correct values. The maximum size of
 433                  * the eden and survivor spaces are supposed to be:
 434                  *    max_eden_size = new_size - (2*alignment).
 435                  *    max_survivor_size = new_size - (2*alignment).
 436                  * since we don't know the alignment value used, and because
 437                  * of other parallel scavenge bugs that result in oversized
 438                  * spaces, we just set the maximum size of each space to the
 439                  * full new gen size.
 440                  */
 441                 Monitor monitor = null;
 442 
 443                 LongBuffer lb = LongBuffer.allocate(1);
 444                 lb.put(new_max.longValue());
 445                 monitor = new PerfLongMonitor(eden_size, Units.BYTES,
 446                                               Variability.CONSTANT, false, lb);
 447                 map.put(eden_size, monitor);
 448 
 449                 monitor = new PerfLongMonitor(s0_size, Units.BYTES,
 450                                               Variability.CONSTANT, false, lb);
 451                 map.put(s0_size, monitor);
 452 
 453                 monitor = new PerfLongMonitor(s1_size, Units.BYTES,
 454                                               Variability.CONSTANT, false, lb);
 455                 map.put(s1_size, monitor);
 456             }
 457         }
 458     }
 459 
 460     /**
 461      * method to extract the next monitor entry from the instrumentation memory.
 462      * assumes that nextEntry is the offset into the byte array
 463      * at which to start the search for the next entry. method leaves
 464      * next entry pointing to the next entry or to the end of data.
 465      */
 466     protected Monitor getNextMonitorEntry() throws MonitorException {
 467         Monitor monitor = null;
 468 
 469         // entries are always 4 byte aligned.
 470         if ((nextEntry % 4) != 0) {
 471             throw new MonitorStructureException(
 472                    "Entry index not properly aligned: " + nextEntry);
 473         }
 474 
 475         // protect against a corrupted shared memory region.
 476         if ((nextEntry < 0) || (nextEntry > buffer.limit())) {
 477             throw new MonitorStructureException(
 478                    "Entry index out of bounds: nextEntry = " + nextEntry
 479                    + ", limit = " + buffer.limit());
 480         }
 481 
 482         // check for the end of the buffer
 483         if (nextEntry == buffer.limit()) {
 484             lognl("getNextMonitorEntry():"
 485                   + " nextEntry == buffer.limit(): returning");
 486             return null;
 487         }
 488 
 489         buffer.position(nextEntry);
 490 
 491         int entryStart = buffer.position();
 492         int entryLength = buffer.getInt();
 493 
 494         // check for valid entry length
 495         if ((entryLength < 0) || (entryLength > buffer.limit())) {
 496             throw new MonitorStructureException(
 497                    "Invalid entry length: entryLength = " + entryLength);
 498         }
 499 
 500         // check if last entry occurs before the eof.
 501         if ((entryStart + entryLength) > buffer.limit()) {
 502             throw new MonitorStructureException(
 503                    "Entry extends beyond end of buffer: "
 504                    + " entryStart = " + entryStart
 505                    + " entryLength = " + entryLength
 506                    + " buffer limit = " + buffer.limit());
 507         }
 508 
 509         if (entryLength == 0) {
 510             // end of data
 511             return null;
 512         }
 513 
 514         int nameLength = buffer.getInt();
 515         int vectorLength = buffer.getInt();
 516         byte dataType = buffer.get();
 517         byte flags = buffer.get();
 518         Units u = Units.toUnits(buffer.get());
 519         Variability v = Variability.toVariability(buffer.get());
 520         boolean supported = (flags & 0x01) != 0;
 521 
 522         // defend against corrupt entries
 523         if ((nameLength <= 0) || (nameLength > entryLength)) {
 524             throw new MonitorStructureException(
 525                    "Invalid Monitor name length: " + nameLength);
 526         }
 527 
 528         if ((vectorLength < 0) || (vectorLength > entryLength)) {
 529             throw new MonitorStructureException(
 530                    "Invalid Monitor vector length: " + vectorLength);
 531         }
 532 
 533         // read in the perfData item name, casting bytes to chars. skip the
 534         // null terminator
 535         //
 536         byte[] nameBytes = new byte[nameLength-1];
 537         for (int i = 0; i < nameLength-1; i++) {
 538             nameBytes[i] = buffer.get();
 539         }
 540 
 541         // convert name into a String
 542         String name = new String(nameBytes, 0, nameLength-1);
 543 
 544         if (v == Variability.INVALID) {
 545             throw new MonitorDataException("Invalid variability attribute:"
 546                                            + " entry index = " + perfDataItem
 547                                            + " name = " + name);
 548         }
 549         if (u == Units.INVALID) {
 550             throw new MonitorDataException("Invalid units attribute: "
 551                                            + " entry index = " + perfDataItem
 552                                            + " name = " + name);
 553         }
 554 
 555         int offset;
 556         if (vectorLength == 0) {
 557             // scalar Types
 558             if (dataType == BasicType.LONG.intValue()) {
 559                 offset = entryStart + entryLength - 8;  /* 8 = sizeof(long) */
 560                 buffer.position(offset);
 561                 LongBuffer lb = buffer.asLongBuffer();
 562                 lb.limit(1);
 563                 monitor = new PerfLongMonitor(name, u, v, supported, lb);
 564                 perfDataItem++;
 565             } else {
 566                 // bad data types.
 567                 throw new MonitorTypeException("Invalid Monitor type:"
 568                                     + " entry index = " + perfDataItem
 569                                     + " name = " + name
 570                                     + " type = " + dataType);
 571             }
 572         } else {
 573             // vector types
 574             if (dataType == BasicType.BYTE.intValue()) {
 575                 if (u != Units.STRING) {
 576                     // only byte arrays of type STRING are currently supported
 577                     throw new MonitorTypeException("Invalid Monitor type:"
 578                                       + " entry index = " + perfDataItem
 579                                       + " name = " + name
 580                                       + " type = " + dataType);
 581                 }
 582 
 583                 offset = entryStart + PERFDATA_NAME_OFFSET + nameLength;
 584                 buffer.position(offset);
 585                 ByteBuffer bb = buffer.slice();
 586                 bb.limit(vectorLength);
 587                 bb.position(0);
 588 
 589                 if (v == Variability.CONSTANT) {
 590                     monitor = new PerfStringConstantMonitor(name, supported,
 591                                                             bb);
 592                 } else if (v == Variability.VARIABLE) {
 593                     monitor = new PerfStringVariableMonitor(name, supported,
 594                                                             bb, vectorLength-1);
 595                 } else {
 596                     // Monotonically increasing byte arrays are not supported
 597                     throw new MonitorDataException(
 598                             "Invalid variability attribute:"
 599                             + " entry index = " + perfDataItem
 600                             + " name = " + name
 601                             + " variability = " + v);
 602                 }
 603                 perfDataItem++;
 604             } else {
 605                 // bad data types.
 606                 throw new MonitorTypeException(
 607                         "Invalid Monitor type:" + " entry index = "
 608                         + perfDataItem + " name = " + name
 609                         + " type = " + dataType);
 610             }
 611         }
 612 
 613         // setup index to next entry for next iteration of the loop.
 614         nextEntry = entryStart + entryLength;
 615         return monitor;
 616     }
 617 
 618     /**
 619      * Method to dump debugging information
 620      */
 621     private void dumpAll(Map map, int lvmid) {
 622         if (DEBUG) {
 623             Set keys = map.keySet();
 624 
 625             System.err.println("Dump for " + lvmid);
 626             int j = 0;
 627             for (Iterator i = keys.iterator(); i.hasNext(); j++) {
 628                 Monitor monitor = (Monitor)map.get(i.next());
 629                 System.err.println(j + "\t" + monitor.getName()
 630                                    + "=" + monitor.getValue());
 631             }
 632             System.err.println("nextEntry = " + nextEntry
 633                                + " pollForEntry = " + pollForEntry);
 634             System.err.println("Buffer info:");
 635             System.err.println("buffer = " + buffer);
 636         }
 637     }
 638 
 639     private void lognl(String s) {
 640         if (DEBUG) {
 641             System.err.println(s);
 642         }
 643     }
 644 
 645     private void log(String s) {
 646         if (DEBUG) {
 647             System.err.print(s);
 648         }
 649     }
 650 }