1 /*
   2  * Copyright (c) 2004, 2017, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.runtime;
  26 
  27 import java.util.*;
  28 import sun.jvm.hotspot.debugger.*;
  29 import sun.jvm.hotspot.oops.*;
  30 import sun.jvm.hotspot.types.*;
  31 import sun.jvm.hotspot.utilities.*;
  32 
  33 public class PerfDataEntry extends VMObject {
  34     private static JIntField  entryLengthField;
  35     private static JIntField  nameOffsetField;
  36     private static JIntField  vectorLengthField;
  37     private static JByteField dataTypeField;
  38     private static JByteField flagsField;
  39     private static JByteField dataUnitsField;
  40     private static JByteField dataVariabilityField;
  41     private static JIntField  dataOffsetField;
  42 
  43     static {
  44         VM.registerVMInitializedObserver(new Observer() {
  45                 public void update(Observable o, Object data) {
  46                     initialize(VM.getVM().getTypeDataBase());
  47                 }
  48             });
  49     }
  50 
  51     private static synchronized void initialize(TypeDataBase db) {
  52         Type type = db.lookupType("PerfDataEntry");
  53         entryLengthField = type.getJIntField("entry_length");
  54         nameOffsetField = type.getJIntField("name_offset");
  55         vectorLengthField = type.getJIntField("vector_length");
  56         dataTypeField = type.getJByteField("data_type");
  57         flagsField = type.getJByteField("flags");
  58         dataUnitsField = type.getJByteField("data_units");
  59         dataVariabilityField = type.getJByteField("data_variability");
  60         dataOffsetField = type.getJIntField("data_offset");
  61     }
  62 
  63     public PerfDataEntry(Address addr) {
  64         super(addr);
  65     }
  66 
  67     // Accessors
  68 
  69     public int entryLength() {
  70         return (int) entryLengthField.getValue(addr);
  71     }
  72 
  73     public int nameOffset() {
  74         return (int) nameOffsetField.getValue(addr);
  75     }
  76 
  77     public int vectorLength() {
  78         return (int) vectorLengthField.getValue(addr);
  79     }
  80 
  81     // returns one of the constants in BasicType class
  82     public int dataType() {
  83         char ch = (char) (byte) dataTypeField.getValue(addr);
  84         return BasicType.charToType(ch);
  85     }
  86 
  87     public byte flags() {
  88         return (byte) flagsField.getValue(addr);
  89     }
  90 
  91     public boolean supported() {
  92         return (flags() & 0x1) != 0;
  93     }
  94 
  95     private static class PerfDataUnits {
  96         public static int U_None;
  97         public static int U_Bytes;
  98         public static int U_Ticks;
  99         public static int U_Events;
 100         public static int U_String;
 101         public static int U_Hertz;
 102 
 103         static {
 104             VM.registerVMInitializedObserver(new Observer() {
 105                 public void update(Observable o, Object data) {
 106                     initialize(VM.getVM().getTypeDataBase());
 107                 }
 108             });
 109         }
 110         private static synchronized void initialize(TypeDataBase db) {
 111             U_None = db.lookupIntConstant("PerfData::U_None");
 112             U_Bytes = db.lookupIntConstant("PerfData::U_Bytes");
 113             U_Ticks = db.lookupIntConstant("PerfData::U_Ticks");
 114             U_Events = db.lookupIntConstant("PerfData::U_Events");
 115             U_String = db.lookupIntConstant("PerfData::U_String");
 116             U_Hertz = db.lookupIntConstant("PerfData::U_Hertz");
 117         }
 118     }
 119 
 120     // returns one of the constants in PerfDataUnits
 121     public int dataUnits() {
 122         return (int) dataUnitsField.getValue(addr);
 123     }
 124 
 125     // returns one of the constants in PerfDataVariability
 126     public int dataVariability() {
 127         return (int) dataVariabilityField.getValue(addr);
 128     }
 129 
 130     public int dataOffset() {
 131         return (int) dataOffsetField.getValue(addr);
 132     }
 133 
 134     public String name() {
 135         int off = nameOffset();
 136         return CStringUtilities.getString(addr.addOffsetTo(off));
 137     }
 138 
 139     public boolean booleanValue() {
 140         if (Assert.ASSERTS_ENABLED) {
 141             Assert.that(vectorLength() == 0 &&
 142                         dataType() == BasicType.getTBoolean(), "not a boolean");
 143         }
 144         return addr.getJBooleanAt(dataOffset());
 145     }
 146 
 147     public char charValue() {
 148         if (Assert.ASSERTS_ENABLED) {
 149             Assert.that(vectorLength() == 0 &&
 150                         dataType() == BasicType.getTChar(), "not a char");
 151         }
 152         return addr.getJCharAt(dataOffset());
 153     }
 154 
 155     public byte byteValue() {
 156         if (Assert.ASSERTS_ENABLED) {
 157             Assert.that(vectorLength() == 0 &&
 158                         dataType() == BasicType.getTByte(), "not a byte");
 159         }
 160         return addr.getJByteAt(dataOffset());
 161 
 162     }
 163 
 164     public short shortValue() {
 165         if (Assert.ASSERTS_ENABLED) {
 166             Assert.that(vectorLength() == 0 &&
 167                         dataType() == BasicType.getTShort(), "not a short");
 168         }
 169         return addr.getJShortAt(dataOffset());
 170     }
 171 
 172     public int intValue() {
 173         if (Assert.ASSERTS_ENABLED) {
 174             Assert.that(vectorLength() == 0 &&
 175                         dataType() == BasicType.getTInt(), "not an int");
 176         }
 177         return addr.getJIntAt(dataOffset());
 178     }
 179 
 180     public long longValue() {
 181         if (Assert.ASSERTS_ENABLED) {
 182             Assert.that(vectorLength() == 0 &&
 183                         dataType() == BasicType.getTLong(), "not a long");
 184         }
 185         return addr.getJLongAt(dataOffset());
 186     }
 187 
 188     public float floatValue() {
 189         if (Assert.ASSERTS_ENABLED) {
 190             Assert.that(vectorLength() == 0 &&
 191                         dataType() == BasicType.getTFloat(), "not a float");
 192         }
 193         return addr.getJFloatAt(dataOffset());
 194     }
 195 
 196     public double doubleValue() {
 197         if (Assert.ASSERTS_ENABLED) {
 198             Assert.that(vectorLength() == 0 &&
 199                         dataType() == BasicType.getTDouble(), "not a double");
 200         }
 201         return addr.getJDoubleAt(dataOffset());
 202     }
 203 
 204     public boolean[] booleanArrayValue() {
 205         int len = vectorLength();
 206         if (Assert.ASSERTS_ENABLED) {
 207             Assert.that(len > 0 &&
 208                         dataType() == BasicType.getTBoolean(), "not a boolean vector");
 209         }
 210         boolean[] res = new boolean[len];
 211         final int off = dataOffset();
 212         final long size =  getHeap().getBooleanSize();
 213         for (int i = 0; i < len; i++) {
 214             res[i] = addr.getJBooleanAt(off + i * size);
 215         }
 216         return res;
 217     }
 218 
 219     public char[] charArrayValue() {
 220         int len = vectorLength();
 221         if (Assert.ASSERTS_ENABLED) {
 222             Assert.that(len > 0 &&
 223                         dataType() == BasicType.getTChar(), "not a char vector");
 224         }
 225         char[] res = new char[len];
 226         final int off = dataOffset();
 227         final long size = getHeap().getCharSize();
 228         for (int i = 0; i < len; i++) {
 229             res[i] = addr.getJCharAt(off + i * size);
 230         }
 231         return res;
 232     }
 233 
 234     public byte[] byteArrayValue() {
 235         int len = vectorLength();
 236         if (Assert.ASSERTS_ENABLED) {
 237             Assert.that(len > 0 &&
 238                         dataType() == BasicType.getTByte(), "not a byte vector");
 239         }
 240         byte[] res = new byte[len];
 241         final int off = dataOffset();
 242         final long size = getHeap().getByteSize();
 243         for (int i = 0; i < len; i++) {
 244             res[i] = addr.getJByteAt(off + i * size);
 245         }
 246         return res;
 247     }
 248 
 249     public short[] shortArrayValue() {
 250         int len = vectorLength();
 251         if (Assert.ASSERTS_ENABLED) {
 252             Assert.that(len > 0 &&
 253                         dataType() == BasicType.getTShort(), "not a short vector");
 254         }
 255         short[] res = new short[len];
 256         final int off = dataOffset();
 257         final long size = getHeap().getShortSize();
 258         for (int i = 0; i < len; i++) {
 259             res[i] = addr.getJShortAt(off + i * size);
 260         }
 261         return res;
 262     }
 263 
 264     public int[] intArrayValue() {
 265         int len = vectorLength();
 266         if (Assert.ASSERTS_ENABLED) {
 267             Assert.that(len > 0 &&
 268                         dataType() == BasicType.getTInt(), "not an int vector");
 269         }
 270         int[] res = new int[len];
 271         final int off = dataOffset();
 272         final long size = getHeap().getIntSize();
 273         for (int i = 0; i < len; i++) {
 274             res[i] = addr.getJIntAt(off + i * size);
 275         }
 276         return res;
 277     }
 278 
 279     public long[] longArrayValue() {
 280         int len = vectorLength();
 281         if (Assert.ASSERTS_ENABLED) {
 282             Assert.that(len > 0 &&
 283                         dataType() == BasicType.getTLong(), "not a long vector");
 284         }
 285         long[] res = new long[len];
 286         final int off = dataOffset();
 287         final long size = getHeap().getLongSize();
 288         for (int i = 0; i < len; i++) {
 289             res[i] = addr.getJLongAt(off + i * size);
 290         }
 291         return res;
 292     }
 293 
 294     public float[] floatArrayValue() {
 295         int len = vectorLength();
 296         if (Assert.ASSERTS_ENABLED) {
 297             Assert.that(len > 0 &&
 298                         dataType() == BasicType.getTFloat(), "not a float vector");
 299         }
 300         float[] res = new float[len];
 301         final int off = dataOffset();
 302         final long size = getHeap().getFloatSize();
 303         for (int i = 0; i < len; i++) {
 304             res[i] = addr.getJFloatAt(off + i * size);
 305         }
 306         return res;
 307     }
 308 
 309     public double[] doubleArrayValue() {
 310         int len = vectorLength();
 311         if (Assert.ASSERTS_ENABLED) {
 312             Assert.that(len > 0 &&
 313                         dataType() == BasicType.getTDouble(), "not a double vector");
 314         }
 315         double[] res = new double[len];
 316         final int off = dataOffset();
 317         final long size = getHeap().getDoubleSize();
 318         for (int i = 0; i < len; i++) {
 319             res[i] = addr.getJDoubleAt(off + i * size);
 320         }
 321         return res;
 322     }
 323 
 324     // value as String
 325     public String valueAsString() {
 326         int dataType = dataType();
 327         int len = vectorLength();
 328         String str = null;
 329         if (len == 0) { // scalar
 330             if (dataType == BasicType.getTBoolean()) {
 331                 str = Boolean.toString(booleanValue());
 332             } else if (dataType == BasicType.getTChar()) {
 333                 str = "'" + Character.toString(charValue()) + "'";
 334             } else if (dataType == BasicType.getTByte()) {
 335                 str = Byte.toString(byteValue());
 336             } else if (dataType == BasicType.getTShort()) {
 337                 str = Short.toString(shortValue());
 338             } else if (dataType ==  BasicType.getTInt()) {
 339                 str = Integer.toString(intValue());
 340             } else if (dataType == BasicType.getTLong()) {
 341                 str = Long.toString(longValue());
 342             } else if (dataType == BasicType.getTFloat()) {
 343                 str = Float.toString(floatValue());
 344             } else if (dataType == BasicType.getTDouble()) {
 345                 str = Double.toString(doubleValue());
 346             } else {
 347                 str = "<unknown scalar value>";
 348             }
 349         } else { // vector
 350             if (dataType == BasicType.getTBoolean()) {
 351                 boolean[] res = booleanArrayValue();
 352                 StringBuffer buf = new StringBuffer();
 353                 buf.append('[');
 354                 for (int i = 0; i < res.length; i++) {
 355                     buf.append(Boolean.toString(res[i]));
 356                     buf.append(", ");
 357                 }
 358                 buf.append(']');
 359                 str = buf.toString();
 360             } else if (dataType == BasicType.getTChar()) {
 361                 // char[] is returned as a String
 362                 str = new String(charArrayValue());
 363             } else if (dataType == BasicType.getTByte()) {
 364                 // byte[] is returned as a String
 365                 try {
 366                     str = new String(byteArrayValue(), "US-ASCII");
 367                 } catch (java.io.UnsupportedEncodingException e) {
 368                     str = "can't decode string : " + e.getMessage();
 369                 }
 370             } else if (dataType == BasicType.getTShort()) {
 371                 short[] res = shortArrayValue();
 372                 StringBuffer buf = new StringBuffer();
 373                 buf.append('[');
 374                 for (int i = 0; i < res.length; i++) {
 375                     buf.append(Short.toString(res[i]));
 376                     buf.append(", ");
 377                 }
 378                 buf.append(']');
 379                 str = buf.toString();
 380             } else if (dataType ==  BasicType.getTInt()) {
 381                 int[] res = intArrayValue();
 382                 StringBuffer buf = new StringBuffer();
 383                 buf.append('[');
 384                 for (int i = 0; i < res.length; i++) {
 385                     buf.append(Integer.toString(res[i]));
 386                     buf.append(", ");
 387                 }
 388                 buf.append(']');
 389                 str = buf.toString();
 390             } else if (dataType == BasicType.getTLong()) {
 391                 long[] res = longArrayValue();
 392                 StringBuffer buf = new StringBuffer();
 393                 buf.append('[');
 394                 for (int i = 0; i < res.length; i++) {
 395                     buf.append(Long.toString(res[i]));
 396                     buf.append(", ");
 397                 }
 398                 buf.append(']');
 399                 str = buf.toString();
 400             } else if (dataType == BasicType.getTFloat()) {
 401                 float[] res = floatArrayValue();
 402                 StringBuffer buf = new StringBuffer();
 403                 buf.append('[');
 404                 for (int i = 0; i < res.length; i++) {
 405                     buf.append(Float.toString(res[i]));
 406                     buf.append(", ");
 407                 }
 408                 buf.append(']');
 409                 str = buf.toString();
 410             } else if (dataType == BasicType.getTDouble()) {
 411                 double[] res = doubleArrayValue();
 412                 StringBuffer buf = new StringBuffer();
 413                 buf.append('[');
 414                 for (int i = 0; i < res.length; i++) {
 415                     buf.append(Double.toString(res[i]));
 416                     buf.append(", ");
 417                 }
 418                 buf.append(']');
 419                 str = buf.toString();
 420             } else {
 421                 str = "<unknown vector value>";
 422             }
 423         }
 424 
 425         // add units
 426         int dataUnitsValue = dataUnits();
 427 
 428         if (dataUnitsValue == PerfDataUnits.U_Bytes) {
 429             str += " byte(s)";
 430         } else if (dataUnitsValue == PerfDataUnits.U_Ticks) {
 431             str += " tick(s)";
 432         } else if (dataUnitsValue == PerfDataUnits.U_Events) {
 433             str += " event(s)";
 434         } else if (dataUnitsValue == PerfDataUnits.U_Hertz) {
 435             str += " Hz";
 436         }
 437 
 438         return str;
 439     }
 440 
 441     // -- Internals only below this point
 442     private ObjectHeap getHeap() {
 443         return VM.getVM().getObjectHeap();
 444     }
 445 }