|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.jvmstat.perfdata.monitor.v2_0; |
|
|
|
import sun.jvmstat.monitor.*; |
|
import sun.jvmstat.perfdata.monitor.*; |
|
import java.util.*; |
|
import java.util.regex.*; |
|
import java.nio.*; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public class PerfDataBuffer extends PerfDataBufferImpl { |
|
|
|
private static final boolean DEBUG = false; |
|
private static final int syncWaitMs = |
|
Integer.getInteger("sun.jvmstat.perdata.syncWaitMs", 5000); |
|
private static final ArrayList EMPTY_LIST = new ArrayList(0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private final static int PERFDATA_ENTRYLENGTH_OFFSET=0; |
|
private final static int PERFDATA_ENTRYLENGTH_SIZE=4; |
|
private final static int PERFDATA_NAMEOFFSET_OFFSET=4; |
|
private final static int PERFDATA_NAMEOFFSET_SIZE=4; |
|
private final static int PERFDATA_VECTORLENGTH_OFFSET=8; |
|
private final static int PERFDATA_VECTORLENGTH_SIZE=4; |
|
private final static int PERFDATA_DATATYPE_OFFSET=12; |
|
private final static int PERFDATA_DATATYPE_SIZE=1; |
|
private final static int PERFDATA_FLAGS_OFFSET=13; |
|
private final static int PERFDATA_FLAGS_SIZE=1; |
|
private final static int PERFDATA_DATAUNITS_OFFSET=14; |
|
private final static int PERFDATA_DATAUNITS_SIZE=1; |
|
private final static int PERFDATA_DATAVAR_OFFSET=15; |
|
private final static int PERFDATA_DATAVAR_SIZE=1; |
|
private final static int PERFDATA_DATAOFFSET_OFFSET=16; |
|
private final static int PERFDATA_DATAOFFSET_SIZE=4; |
|
|
|
PerfDataBufferPrologue prologue; |
|
int nextEntry; |
|
long lastNumEntries; |
|
IntegerMonitor overflow; |
|
ArrayList<Monitor> insertedMonitors; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public PerfDataBuffer(ByteBuffer buffer, int lvmid) |
|
throws MonitorException { |
|
super(buffer, lvmid); |
|
prologue = new PerfDataBufferPrologue(buffer); |
|
this.buffer.order(prologue.getByteOrder()); |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected void buildMonitorMap(Map<String, Monitor> map) throws MonitorException { |
|
assert Thread.holdsLock(this); |
|
|
|
|
|
buffer.rewind(); |
|
|
|
|
|
buildPseudoMonitors(map); |
|
|
|
// wait for the target JVM to indicate that it's intrumentation |
|
|
|
synchWithTarget(); |
|
|
|
|
|
nextEntry = prologue.getEntryOffset(); |
|
|
|
|
|
int numEntries = prologue.getNumEntries(); |
|
|
|
|
|
Monitor monitor = getNextMonitorEntry(); |
|
while (monitor != null) { |
|
map.put(monitor.getName(), monitor); |
|
monitor = getNextMonitorEntry(); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
lastNumEntries = numEntries; |
|
|
|
|
|
insertedMonitors = new ArrayList<Monitor>(map.values()); |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected void getNewMonitors(Map<String, Monitor> map) throws MonitorException { |
|
assert Thread.holdsLock(this); |
|
|
|
int numEntries = prologue.getNumEntries(); |
|
|
|
if (numEntries > lastNumEntries) { |
|
lastNumEntries = numEntries; |
|
Monitor monitor = getNextMonitorEntry(); |
|
|
|
while (monitor != null) { |
|
String name = monitor.getName(); |
|
|
|
|
|
if (!map.containsKey(name)) { |
|
map.put(name, monitor); |
|
if (insertedMonitors != null) { |
|
insertedMonitors.add(monitor); |
|
} |
|
} |
|
monitor = getNextMonitorEntry(); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected MonitorStatus getMonitorStatus(Map<String, Monitor> map) throws MonitorException { |
|
assert Thread.holdsLock(this); |
|
assert insertedMonitors != null; |
|
|
|
|
|
getNewMonitors(map); |
|
|
|
|
|
ArrayList removed = EMPTY_LIST; |
|
ArrayList inserted = insertedMonitors; |
|
|
|
insertedMonitors = new ArrayList<Monitor>(); |
|
return new MonitorStatus(inserted, removed); |
|
} |
|
|
|
|
|
|
|
*/ |
|
protected void buildPseudoMonitors(Map<String, Monitor> map) { |
|
Monitor monitor = null; |
|
String name = null; |
|
IntBuffer ib = null; |
|
|
|
name = PerfDataBufferPrologue.PERFDATA_MAJOR_NAME; |
|
ib = prologue.majorVersionBuffer(); |
|
monitor = new PerfIntegerMonitor(name, Units.NONE, |
|
Variability.CONSTANT, false, ib); |
|
map.put(name, monitor); |
|
|
|
name = PerfDataBufferPrologue.PERFDATA_MINOR_NAME; |
|
ib = prologue.minorVersionBuffer(); |
|
monitor = new PerfIntegerMonitor(name, Units.NONE, |
|
Variability.CONSTANT, false, ib); |
|
map.put(name, monitor); |
|
|
|
name = PerfDataBufferPrologue.PERFDATA_BUFFER_SIZE_NAME; |
|
ib = prologue.sizeBuffer(); |
|
monitor = new PerfIntegerMonitor(name, Units.BYTES, |
|
Variability.MONOTONIC, false, ib); |
|
map.put(name, monitor); |
|
|
|
name = PerfDataBufferPrologue.PERFDATA_BUFFER_USED_NAME; |
|
ib = prologue.usedBuffer(); |
|
monitor = new PerfIntegerMonitor(name, Units.BYTES, |
|
Variability.MONOTONIC, false, ib); |
|
map.put(name, monitor); |
|
|
|
name = PerfDataBufferPrologue.PERFDATA_OVERFLOW_NAME; |
|
ib = prologue.overflowBuffer(); |
|
monitor = new PerfIntegerMonitor(name, Units.BYTES, |
|
Variability.MONOTONIC, false, ib); |
|
map.put(name, monitor); |
|
this.overflow = (IntegerMonitor)monitor; |
|
|
|
name = PerfDataBufferPrologue.PERFDATA_MODTIMESTAMP_NAME; |
|
LongBuffer lb = prologue.modificationTimeStampBuffer(); |
|
monitor = new PerfLongMonitor(name, Units.TICKS, |
|
Variability.MONOTONIC, false, lb); |
|
map.put(name, monitor); |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
protected void synchWithTarget() throws MonitorException { |
|
|
|
|
|
|
|
|
|
*/ |
|
long timeLimit = System.currentTimeMillis() + syncWaitMs; |
|
|
|
|
|
log("synchWithTarget: " + lvmid + " "); |
|
while (!prologue.isAccessible()) { |
|
|
|
log("."); |
|
|
|
|
|
try { Thread.sleep(20); } catch (InterruptedException e) { } |
|
|
|
if (System.currentTimeMillis() > timeLimit) { |
|
logln("failed: " + lvmid); |
|
throw new MonitorException("Could not synchronize with target"); |
|
} |
|
} |
|
logln("success: " + lvmid); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
protected Monitor getNextMonitorEntry() throws MonitorException { |
|
Monitor monitor = null; |
|
|
|
|
|
if ((nextEntry % 4) != 0) { |
|
throw new MonitorStructureException( |
|
"Misaligned entry index: " |
|
+ Integer.toHexString(nextEntry)); |
|
} |
|
|
|
|
|
if ((nextEntry < 0) || (nextEntry > buffer.limit())) { |
|
throw new MonitorStructureException( |
|
"Entry index out of bounds: " |
|
+ Integer.toHexString(nextEntry) |
|
+ ", limit = " + Integer.toHexString(buffer.limit())); |
|
} |
|
|
|
|
|
if (nextEntry == buffer.limit()) { |
|
logln("getNextMonitorEntry():" |
|
+ " nextEntry == buffer.limit(): returning"); |
|
return null; |
|
} |
|
|
|
buffer.position(nextEntry); |
|
|
|
int entryStart = buffer.position(); |
|
int entryLength = buffer.getInt(); |
|
|
|
|
|
if ((entryLength < 0) || (entryLength > buffer.limit())) { |
|
throw new MonitorStructureException( |
|
"Invalid entry length: entryLength = " + entryLength |
|
+ " (0x" + Integer.toHexString(entryLength) + ")"); |
|
} |
|
|
|
|
|
if ((entryStart + entryLength) > buffer.limit()) { |
|
throw new MonitorStructureException( |
|
"Entry extends beyond end of buffer: " |
|
+ " entryStart = 0x" + Integer.toHexString(entryStart) |
|
+ " entryLength = 0x" + Integer.toHexString(entryLength) |
|
+ " buffer limit = 0x" + Integer.toHexString(buffer.limit())); |
|
} |
|
|
|
if (entryLength == 0) { |
|
|
|
return null; |
|
} |
|
|
|
|
|
int nameOffset = buffer.getInt(); |
|
int vectorLength = buffer.getInt(); |
|
byte typeCodeByte = buffer.get(); |
|
byte flags = buffer.get(); |
|
byte unitsByte = buffer.get(); |
|
byte varByte = buffer.get(); |
|
int dataOffset = buffer.getInt(); |
|
|
|
dump_entry_fixed(entryStart, nameOffset, vectorLength, typeCodeByte, |
|
flags, unitsByte, varByte, dataOffset); |
|
|
|
|
|
Units units = Units.toUnits(unitsByte); |
|
Variability variability = Variability.toVariability(varByte); |
|
TypeCode typeCode = null; |
|
boolean supported = (flags & 0x01) != 0; |
|
|
|
try { |
|
typeCode = TypeCode.toTypeCode(typeCodeByte); |
|
|
|
} catch (IllegalArgumentException e) { |
|
throw new MonitorStructureException( |
|
"Illegal type code encountered:" |
|
+ " entry_offset = 0x" + Integer.toHexString(nextEntry) |
|
+ ", type_code = " + Integer.toHexString(typeCodeByte)); |
|
} |
|
|
|
|
|
if (nameOffset > entryLength) { |
|
throw new MonitorStructureException( |
|
"Field extends beyond entry bounds" |
|
+ " entry_offset = 0x" + Integer.toHexString(nextEntry) |
|
+ ", name_offset = 0x" + Integer.toHexString(nameOffset)); |
|
} |
|
|
|
|
|
if (dataOffset > entryLength) { |
|
throw new MonitorStructureException( |
|
"Field extends beyond entry bounds:" |
|
+ " entry_offset = 0x" + Integer.toHexString(nextEntry) |
|
+ ", data_offset = 0x" + Integer.toHexString(dataOffset)); |
|
} |
|
|
|
|
|
if (variability == Variability.INVALID) { |
|
throw new MonitorDataException( |
|
"Invalid variability attribute:" |
|
+ " entry_offset = 0x" + Integer.toHexString(nextEntry) |
|
+ ", variability = 0x" + Integer.toHexString(varByte)); |
|
} |
|
|
|
if (units == Units.INVALID) { |
|
throw new MonitorDataException( |
|
"Invalid units attribute: entry_offset = 0x" |
|
+ Integer.toHexString(nextEntry) |
|
+ ", units = 0x" + Integer.toHexString(unitsByte)); |
|
} |
|
|
|
// the entry looks good - parse the variable length components |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
assert (buffer.position() == (entryStart + nameOffset)); |
|
assert (dataOffset > nameOffset); |
|
|
|
|
|
int maxNameLength = dataOffset-nameOffset; |
|
|
|
|
|
assert (maxNameLength < entryLength); |
|
|
|
// collect the characters, but do not collect the null byte, |
|
|
|
byte[] nameBytes = new byte[maxNameLength]; |
|
int nameLength = 0; |
|
byte b; |
|
while (((b = buffer.get()) != 0) && (nameLength < maxNameLength)) { |
|
nameBytes[nameLength++] = b; |
|
} |
|
|
|
assert (nameLength < maxNameLength); |
|
|
|
|
|
assert (buffer.position() <= (entryStart + dataOffset)); |
|
|
|
|
|
String name = new String(nameBytes, 0, nameLength); |
|
|
|
|
|
|
|
|
|
*/ |
|
int dataSize = entryLength - dataOffset; |
|
|
|
|
|
buffer.position(entryStart + dataOffset); |
|
|
|
dump_entry_variable(name, buffer, dataSize); |
|
|
|
if (vectorLength == 0) { |
|
|
|
if (typeCode == TypeCode.LONG) { |
|
LongBuffer lb = buffer.asLongBuffer(); |
|
lb.limit(1); |
|
monitor = new PerfLongMonitor(name, units, variability, |
|
supported, lb); |
|
} else { |
|
|
|
|
|
|
|
*/ |
|
throw new MonitorTypeException( |
|
"Unexpected type code encountered:" |
|
+ " entry_offset = 0x" + Integer.toHexString(nextEntry) |
|
+ ", name = " + name |
|
+ ", type_code = " + typeCode |
|
+ " (0x" + Integer.toHexString(typeCodeByte) + ")"); |
|
} |
|
} else { |
|
|
|
if (typeCode == TypeCode.BYTE) { |
|
if (units != Units.STRING) { |
|
|
|
throw new MonitorTypeException( |
|
"Unexpected vector type encounterd:" |
|
+ " entry_offset = " |
|
+ Integer.toHexString(nextEntry) |
|
+ ", name = " + name |
|
+ ", type_code = " + typeCode + " (0x" |
|
+ Integer.toHexString(typeCodeByte) + ")" |
|
+ ", units = " + units + " (0x" |
|
+ Integer.toHexString(unitsByte) + ")"); |
|
} |
|
|
|
ByteBuffer bb = buffer.slice(); |
|
bb.limit(vectorLength); |
|
|
|
if (variability == Variability.CONSTANT) { |
|
monitor = new PerfStringConstantMonitor(name, supported, |
|
bb); |
|
} else if (variability == Variability.VARIABLE) { |
|
monitor = new PerfStringVariableMonitor(name, supported, |
|
bb, vectorLength-1); |
|
} else if (variability == Variability.MONOTONIC) { |
|
|
|
throw new MonitorDataException( |
|
"Unexpected variability attribute:" |
|
+ " entry_offset = 0x" |
|
+ Integer.toHexString(nextEntry) |
|
+ " name = " + name |
|
+ ", variability = " + variability + " (0x" |
|
+ Integer.toHexString(varByte) + ")"); |
|
} else { |
|
|
|
assert false; |
|
} |
|
} else { |
|
|
|
throw new MonitorTypeException( |
|
"Unexpected type code encountered:" |
|
+ " entry_offset = 0x" |
|
+ Integer.toHexString(nextEntry) |
|
+ ", name = " + name |
|
+ ", type_code = " + typeCode + " (0x" |
|
+ Integer.toHexString(typeCodeByte) + ")"); |
|
} |
|
} |
|
|
|
|
|
nextEntry = entryStart + entryLength; |
|
return monitor; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void dumpAll(Map<String, Monitor> map, int lvmid) { |
|
if (DEBUG) { |
|
Set<String> keys = map.keySet(); |
|
|
|
System.err.println("Dump for " + lvmid); |
|
int j = 0; |
|
for (Iterator i = keys.iterator(); i.hasNext(); j++) { |
|
Monitor monitor = map.get(i.next()); |
|
System.err.println(j + "\t" + monitor.getName() |
|
+ "=" + monitor.getValue()); |
|
} |
|
System.err.println("nextEntry = " + nextEntry); |
|
System.err.println("Buffer info:"); |
|
System.err.println("buffer = " + buffer); |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private void dump_entry_fixed(int entry_start, int nameOffset, |
|
int vectorLength, byte typeCodeByte, |
|
byte flags, byte unitsByte, byte varByte, |
|
int dataOffset) { |
|
if (DEBUG) { |
|
System.err.println("Entry at offset: 0x" |
|
+ Integer.toHexString(entry_start)); |
|
System.err.println("\tname_offset = 0x" |
|
+ Integer.toHexString(nameOffset)); |
|
System.err.println("\tvector_length = 0x" |
|
+ Integer.toHexString(vectorLength)); |
|
System.err.println("\tdata_type = 0x" |
|
+ Integer.toHexString(typeCodeByte)); |
|
System.err.println("\tflags = 0x" |
|
+ Integer.toHexString(flags)); |
|
System.err.println("\tdata_units = 0x" |
|
+ Integer.toHexString(unitsByte)); |
|
System.err.println("\tdata_variability = 0x" |
|
+ Integer.toHexString(varByte)); |
|
System.err.println("\tdata_offset = 0x" |
|
+ Integer.toHexString(dataOffset)); |
|
} |
|
} |
|
|
|
private void dump_entry_variable(String name, ByteBuffer bb, int size) { |
|
if (DEBUG) { |
|
char[] toHex = new char[] { '0', '1', '2', '3', |
|
'4', '5', '6', '7', |
|
'8', '9', 'a', 'b', |
|
'c', 'd', 'e', 'f' }; |
|
|
|
ByteBuffer data = bb.slice(); |
|
data.limit(size); |
|
|
|
System.err.println("\tname = " + name); |
|
System.err.println("\tdata = "); |
|
|
|
int count=0; |
|
while (data.hasRemaining()) { |
|
byte b = data.get(); |
|
byte high = (byte)((b >> 8) & 0x0f); |
|
byte low = (byte)(b & 0x0f); |
|
|
|
if (count % 16 == 0) { |
|
System.err.print("\t\t" + Integer.toHexString(count / 16) |
|
+ ": "); |
|
} |
|
|
|
System.err.print(String.valueOf(toHex[high]) |
|
+ String.valueOf(toHex[low])); |
|
|
|
count++; |
|
if (count % 16 == 0) { |
|
System.err.println(); |
|
} else { |
|
System.err.print(" "); |
|
} |
|
} |
|
if (count % 16 != 0) { |
|
System.err.println(); |
|
} |
|
} |
|
} |
|
|
|
private void logln(String s) { |
|
if (DEBUG) { |
|
System.err.println(s); |
|
} |
|
} |
|
|
|
private void log(String s) { |
|
if (DEBUG) { |
|
System.err.print(s); |
|
} |
|
} |
|
} |