/** * method to extract the next monitor entry from the instrumentation memory. assumes that * nextEntry is the offset into the byte array at which to start the search for the next entry. * method leaves next entry pointing to the next entry or to the end of data. */ protected Monitor getNextMonitorEntry() throws MonitorException { Monitor monitor = null; // entries are always 4 byte aligned. if ((nextEntry % 4) != 0) { throw new MonitorStructureException("Entry index not properly aligned: " + nextEntry); } // protect against a corrupted shared memory region. if ((nextEntry < 0) || (nextEntry > buffer.limit())) { throw new MonitorStructureException( "Entry index out of bounds: nextEntry = " + nextEntry + ", limit = " + buffer.limit()); } // check for the end of the buffer if (nextEntry == buffer.limit()) { lognl("getNextMonitorEntry():" + " nextEntry == buffer.limit(): returning"); return null; } buffer.position(nextEntry); int entryStart = buffer.position(); int entryLength = buffer.getInt(); // check for valid entry length if ((entryLength < 0) || (entryLength > buffer.limit())) { throw new MonitorStructureException("Invalid entry length: entryLength = " + entryLength); } // check if last entry occurs before the eof. if ((entryStart + entryLength) > buffer.limit()) { throw new MonitorStructureException( "Entry extends beyond end of buffer: " + " entryStart = " + entryStart + " entryLength = " + entryLength + " buffer limit = " + buffer.limit()); } if (entryLength == 0) { // end of data return null; } int nameLength = buffer.getInt(); int vectorLength = buffer.getInt(); byte dataType = buffer.get(); byte flags = buffer.get(); Units u = Units.toUnits(buffer.get()); Variability v = Variability.toVariability(buffer.get()); boolean supported = (flags & 0x01) != 0; // defend against corrupt entries if ((nameLength <= 0) || (nameLength > entryLength)) { throw new MonitorStructureException("Invalid Monitor name length: " + nameLength); } if ((vectorLength < 0) || (vectorLength > entryLength)) { throw new MonitorStructureException("Invalid Monitor vector length: " + vectorLength); } // read in the perfData item name, casting bytes to chars. skip the // null terminator // byte[] nameBytes = new byte[nameLength - 1]; for (int i = 0; i < nameLength - 1; i++) { nameBytes[i] = buffer.get(); } // convert name into a String String name = new String(nameBytes, 0, nameLength - 1); if (v == Variability.INVALID) { throw new MonitorDataException( "Invalid variability attribute:" + " entry index = " + perfDataItem + " name = " + name); } if (u == Units.INVALID) { throw new MonitorDataException( "Invalid units attribute: " + " entry index = " + perfDataItem + " name = " + name); } int offset; if (vectorLength == 0) { // scalar Types if (dataType == BasicType.LONG.intValue()) { offset = entryStart + entryLength - 8; /* 8 = sizeof(long) */ buffer.position(offset); LongBuffer lb = buffer.asLongBuffer(); lb.limit(1); monitor = new PerfLongMonitor(name, u, v, supported, lb); perfDataItem++; } else { // bad data types. throw new MonitorTypeException( "Invalid Monitor type:" + " entry index = " + perfDataItem + " name = " + name + " type = " + dataType); } } else { // vector types if (dataType == BasicType.BYTE.intValue()) { if (u != Units.STRING) { // only byte arrays of type STRING are currently supported throw new MonitorTypeException( "Invalid Monitor type:" + " entry index = " + perfDataItem + " name = " + name + " type = " + dataType); } offset = entryStart + PERFDATA_NAME_OFFSET + nameLength; buffer.position(offset); ByteBuffer bb = buffer.slice(); bb.limit(vectorLength); bb.position(0); if (v == Variability.CONSTANT) { monitor = new PerfStringConstantMonitor(name, supported, bb); } else if (v == Variability.VARIABLE) { monitor = new PerfStringVariableMonitor(name, supported, bb, vectorLength - 1); } else { // Monotonically increasing byte arrays are not supported throw new MonitorDataException( "Invalid variability attribute:" + " entry index = " + perfDataItem + " name = " + name + " variability = " + v); } perfDataItem++; } else { // bad data types. throw new MonitorTypeException( "Invalid Monitor type:" + " entry index = " + perfDataItem + " name = " + name + " type = " + dataType); } } // setup index to next entry for next iteration of the loop. nextEntry = entryStart + entryLength; return monitor; }
/** * method to repair the 1.4.2 parallel scavenge counters that are incorrectly initialized by the * JVM when UseAdaptiveSizePolicy is set. This bug couldn't be fixed for 1.4.2 FCS due to putback * restrictions. */ private void kludgeMantis(Map<String, Monitor> map, StringMonitor args) { /* * the HotSpot 1.4.2 JVM with the +UseParallelGC option along * with its default +UseAdaptiveSizePolicy option has a bug with * the initialization of the sizes of the eden and survivor spaces. * See bugid 4890736. * * note - use explicit 1.4.2 counter names here - don't update * to latest counter names or attempt to find aliases. */ String cname = "hotspot.gc.collector.0.name"; StringMonitor collector = (StringMonitor) map.get(cname); if (collector.stringValue().compareTo("PSScavenge") == 0) { boolean adaptiveSizePolicy = true; /* * HotSpot processes the -XX:Flags/.hotspotrc arguments prior to * processing the command line arguments. This allows the command * line arguments to override any defaults set in .hotspotrc */ cname = "hotspot.vm.flags"; StringMonitor flags = (StringMonitor) map.get(cname); String allArgs = flags.stringValue() + " " + args.stringValue(); /* * ignore the -XX: prefix as it only applies to the arguments * passed from the command line (i.e. the invocation api). * arguments passed through .hotspotrc omit the -XX: prefix. */ int ahi = allArgs.lastIndexOf("+AggressiveHeap"); int aspi = allArgs.lastIndexOf("-UseAdaptiveSizePolicy"); if (ahi != -1) { /* * +AggressiveHeap was set, check if -UseAdaptiveSizePolicy * is set after +AggressiveHeap. */ // if ((aspi != -1) && (aspi > ahi)) { adaptiveSizePolicy = false; } } else { /* * +AggressiveHeap not set, must be +UseParallelGC. The * relative position of -UseAdaptiveSizePolicy is not * important in this case, as it will override the * UseParallelGC default (+UseAdaptiveSizePolicy) if it * appears anywhere in the JVM arguments. */ if (aspi != -1) { adaptiveSizePolicy = false; } } if (adaptiveSizePolicy) { // adjust the buggy AdaptiveSizePolicy size counters. // first remove the real counters. String eden_size = "hotspot.gc.generation.0.space.0.size"; String s0_size = "hotspot.gc.generation.0.space.1.size"; String s1_size = "hotspot.gc.generation.0.space.2.size"; map.remove(eden_size); map.remove(s0_size); map.remove(s1_size); // get the maximum new generation size String new_max_name = "hotspot.gc.generation.0.capacity.max"; LongMonitor new_max = (LongMonitor) map.get(new_max_name); /* * replace the real counters with pseudo counters that are * initialized to to the correct values. The maximum size of * the eden and survivor spaces are supposed to be: * max_eden_size = new_size - (2*alignment). * max_survivor_size = new_size - (2*alignment). * since we don't know the alignment value used, and because * of other parallel scavenge bugs that result in oversized * spaces, we just set the maximum size of each space to the * full new gen size. */ Monitor monitor = null; LongBuffer lb = LongBuffer.allocate(1); lb.put(new_max.longValue()); monitor = new PerfLongMonitor(eden_size, Units.BYTES, Variability.CONSTANT, false, lb); map.put(eden_size, monitor); monitor = new PerfLongMonitor(s0_size, Units.BYTES, Variability.CONSTANT, false, lb); map.put(s0_size, monitor); monitor = new PerfLongMonitor(s1_size, Units.BYTES, Variability.CONSTANT, false, lb); map.put(s1_size, monitor); } } }