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