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