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     // NOTE: Keep this in sync with PerfData::Units enum in VM code
  96     public interface PerfDataUnits {
  97         public static final int U_None   = 1;
  98         public static final int U_Bytes  = 2;
  99         public static final int U_Ticks  = 3;
 100         public static final int U_Events = 4;
 101         public static final int U_String = 5;
 102         public static final int U_Hertz  = 6;
 103     }
 104 
 105     // returns one of the constants in PerfDataUnits
 106     public int dataUnits() {
 107         return (int) dataUnitsField.getValue(addr);
 108     }
 109 
 110     // NOTE: Keep this in sync with PerfData::Variability enum in VM code
 111     public interface PerfDataVariability {
 112         public static final int V_Constant  = 1;
 113         public static final int V_Monotonic = 2;
 114         public static final int V_Variable  = 3;
 115     }
 116 
 117     // returns one of the constants in PerfDataVariability
 118     public int dataVariability() {
 119         return (int) dataVariabilityField.getValue(addr);
 120     }
 121 
 122     public int dataOffset() {
 123         return (int) dataOffsetField.getValue(addr);
 124     }
 125 
 126     public String name() {
 127         int off = nameOffset();
 128         return CStringUtilities.getString(addr.addOffsetTo(off));
 129     }
 130 
 131     public boolean booleanValue() {
 132         if (Assert.ASSERTS_ENABLED) {
 133             Assert.that(vectorLength() == 0 &&
 134                         dataType() == BasicType.getTBoolean(), "not a boolean");
 135         }
 136         return addr.getJBooleanAt(dataOffset());
 137     }
 138 
 139     public char charValue() {
 140         if (Assert.ASSERTS_ENABLED) {
 141             Assert.that(vectorLength() == 0 &&
 142                         dataType() == BasicType.getTChar(), "not a char");
 143         }
 144         return addr.getJCharAt(dataOffset());
 145     }
 146 
 147     public byte byteValue() {
 148         if (Assert.ASSERTS_ENABLED) {
 149             Assert.that(vectorLength() == 0 &&
 150                         dataType() == BasicType.getTByte(), "not a byte");
 151         }
 152         return addr.getJByteAt(dataOffset());
 153 
 154     }
 155 
 156     public short shortValue() {
 157         if (Assert.ASSERTS_ENABLED) {
 158             Assert.that(vectorLength() == 0 &&
 159                         dataType() == BasicType.getTShort(), "not a short");
 160         }
 161         return addr.getJShortAt(dataOffset());
 162     }
 163 
 164     public int intValue() {
 165         if (Assert.ASSERTS_ENABLED) {
 166             Assert.that(vectorLength() == 0 &&
 167                         dataType() == BasicType.getTInt(), "not an int");
 168         }
 169         return addr.getJIntAt(dataOffset());
 170     }
 171 
 172     public long longValue() {
 173         if (Assert.ASSERTS_ENABLED) {
 174             Assert.that(vectorLength() == 0 &&
 175                         dataType() == BasicType.getTLong(), "not a long");
 176         }
 177         return addr.getJLongAt(dataOffset());
 178     }
 179 
 180     public float floatValue() {
 181         if (Assert.ASSERTS_ENABLED) {
 182             Assert.that(vectorLength() == 0 &&
 183                         dataType() == BasicType.getTFloat(), "not a float");
 184         }
 185         return addr.getJFloatAt(dataOffset());
 186     }
 187 
 188     public double doubleValue() {
 189         if (Assert.ASSERTS_ENABLED) {
 190             Assert.that(vectorLength() == 0 &&
 191                         dataType() == BasicType.getTDouble(), "not a double");
 192         }
 193         return addr.getJDoubleAt(dataOffset());
 194     }
 195 
 196     public boolean[] booleanArrayValue() {
 197         int len = vectorLength();
 198         if (Assert.ASSERTS_ENABLED) {
 199             Assert.that(len > 0 &&
 200                         dataType() == BasicType.getTBoolean(), "not a boolean vector");
 201         }
 202         boolean[] res = new boolean[len];
 203         final int off = dataOffset();
 204         final long size =  getHeap().getBooleanSize();
 205         for (int i = 0; i < len; i++) {
 206             res[i] = addr.getJBooleanAt(off + i * size);
 207         }
 208         return res;
 209     }
 210 
 211     public char[] charArrayValue() {
 212         int len = vectorLength();
 213         if (Assert.ASSERTS_ENABLED) {
 214             Assert.that(len > 0 &&
 215                         dataType() == BasicType.getTChar(), "not a char vector");
 216         }
 217         char[] res = new char[len];
 218         final int off = dataOffset();
 219         final long size = getHeap().getCharSize();
 220         for (int i = 0; i < len; i++) {
 221             res[i] = addr.getJCharAt(off + i * size);
 222         }
 223         return res;
 224     }
 225 
 226     public byte[] byteArrayValue() {
 227         int len = vectorLength();
 228         if (Assert.ASSERTS_ENABLED) {
 229             Assert.that(len > 0 &&
 230                         dataType() == BasicType.getTByte(), "not a byte vector");
 231         }
 232         byte[] res = new byte[len];
 233         final int off = dataOffset();
 234         final long size = getHeap().getByteSize();
 235         for (int i = 0; i < len; i++) {
 236             res[i] = addr.getJByteAt(off + i * size);
 237         }
 238         return res;
 239     }
 240 
 241     public short[] shortArrayValue() {
 242         int len = vectorLength();
 243         if (Assert.ASSERTS_ENABLED) {
 244             Assert.that(len > 0 &&
 245                         dataType() == BasicType.getTShort(), "not a short vector");
 246         }
 247         short[] res = new short[len];
 248         final int off = dataOffset();
 249         final long size = getHeap().getShortSize();
 250         for (int i = 0; i < len; i++) {
 251             res[i] = addr.getJShortAt(off + i * size);
 252         }
 253         return res;
 254     }
 255 
 256     public int[] intArrayValue() {
 257         int len = vectorLength();
 258         if (Assert.ASSERTS_ENABLED) {
 259             Assert.that(len > 0 &&
 260                         dataType() == BasicType.getTInt(), "not an int vector");
 261         }
 262         int[] res = new int[len];
 263         final int off = dataOffset();
 264         final long size = getHeap().getIntSize();
 265         for (int i = 0; i < len; i++) {
 266             res[i] = addr.getJIntAt(off + i * size);
 267         }
 268         return res;
 269     }
 270 
 271     public long[] longArrayValue() {
 272         int len = vectorLength();
 273         if (Assert.ASSERTS_ENABLED) {
 274             Assert.that(len > 0 &&
 275                         dataType() == BasicType.getTLong(), "not a long vector");
 276         }
 277         long[] res = new long[len];
 278         final int off = dataOffset();
 279         final long size = getHeap().getLongSize();
 280         for (int i = 0; i < len; i++) {
 281             res[i] = addr.getJLongAt(off + i * size);
 282         }
 283         return res;
 284     }
 285 
 286     public float[] floatArrayValue() {
 287         int len = vectorLength();
 288         if (Assert.ASSERTS_ENABLED) {
 289             Assert.that(len > 0 &&
 290                         dataType() == BasicType.getTFloat(), "not a float vector");
 291         }
 292         float[] res = new float[len];
 293         final int off = dataOffset();
 294         final long size = getHeap().getFloatSize();
 295         for (int i = 0; i < len; i++) {
 296             res[i] = addr.getJFloatAt(off + i * size);
 297         }
 298         return res;
 299     }
 300 
 301     public double[] doubleArrayValue() {
 302         int len = vectorLength();
 303         if (Assert.ASSERTS_ENABLED) {
 304             Assert.that(len > 0 &&
 305                         dataType() == BasicType.getTDouble(), "not a double vector");
 306         }
 307         double[] res = new double[len];
 308         final int off = dataOffset();
 309         final long size = getHeap().getDoubleSize();
 310         for (int i = 0; i < len; i++) {
 311             res[i] = addr.getJDoubleAt(off + i * size);
 312         }
 313         return res;
 314     }
 315 
 316     // value as String
 317     public String valueAsString() {
 318         int dataType = dataType();
 319         int len = vectorLength();
 320         String str = null;
 321         if (len == 0) { // scalar
 322             if (dataType == BasicType.getTBoolean()) {
 323                 str = Boolean.toString(booleanValue());
 324             } else if (dataType == BasicType.getTChar()) {
 325                 str = "'" + Character.toString(charValue()) + "'";
 326             } else if (dataType == BasicType.getTByte()) {
 327                 str = Byte.toString(byteValue());
 328             } else if (dataType == BasicType.getTShort()) {
 329                 str = Short.toString(shortValue());
 330             } else if (dataType ==  BasicType.getTInt()) {
 331                 str = Integer.toString(intValue());
 332             } else if (dataType == BasicType.getTLong()) {
 333                 str = Long.toString(longValue());
 334             } else if (dataType == BasicType.getTFloat()) {
 335                 str = Float.toString(floatValue());
 336             } else if (dataType == BasicType.getTDouble()) {
 337                 str = Double.toString(doubleValue());
 338             } else {
 339                 str = "<unknown scalar value>";
 340             }
 341         } else { // vector
 342             if (dataType == BasicType.getTBoolean()) {
 343                 boolean[] res = booleanArrayValue();
 344                 StringBuffer buf = new StringBuffer();
 345                 buf.append('[');
 346                 for (int i = 0; i < res.length; i++) {
 347                     buf.append(Boolean.toString(res[i]));
 348                     buf.append(", ");
 349                 }
 350                 buf.append(']');
 351                 str = buf.toString();
 352             } else if (dataType == BasicType.getTChar()) {
 353                 // char[] is returned as a String
 354                 str = new String(charArrayValue());
 355             } else if (dataType == BasicType.getTByte()) {
 356                 // byte[] is returned as a String
 357                 try {
 358                     str = new String(byteArrayValue(), "US-ASCII");
 359                 } catch (java.io.UnsupportedEncodingException e) {
 360                     str = "can't decode string : " + e.getMessage();
 361                 }
 362             } else if (dataType == BasicType.getTShort()) {
 363                 short[] res = shortArrayValue();
 364                 StringBuffer buf = new StringBuffer();
 365                 buf.append('[');
 366                 for (int i = 0; i < res.length; i++) {
 367                     buf.append(Short.toString(res[i]));
 368                     buf.append(", ");
 369                 }
 370                 buf.append(']');
 371                 str = buf.toString();
 372             } else if (dataType ==  BasicType.getTInt()) {
 373                 int[] res = intArrayValue();
 374                 StringBuffer buf = new StringBuffer();
 375                 buf.append('[');
 376                 for (int i = 0; i < res.length; i++) {
 377                     buf.append(Integer.toString(res[i]));
 378                     buf.append(", ");
 379                 }
 380                 buf.append(']');
 381                 str = buf.toString();
 382             } else if (dataType == BasicType.getTLong()) {
 383                 long[] res = longArrayValue();
 384                 StringBuffer buf = new StringBuffer();
 385                 buf.append('[');
 386                 for (int i = 0; i < res.length; i++) {
 387                     buf.append(Long.toString(res[i]));
 388                     buf.append(", ");
 389                 }
 390                 buf.append(']');
 391                 str = buf.toString();
 392             } else if (dataType == BasicType.getTFloat()) {
 393                 float[] res = floatArrayValue();
 394                 StringBuffer buf = new StringBuffer();
 395                 buf.append('[');
 396                 for (int i = 0; i < res.length; i++) {
 397                     buf.append(Float.toString(res[i]));
 398                     buf.append(", ");
 399                 }
 400                 buf.append(']');
 401                 str = buf.toString();
 402             } else if (dataType == BasicType.getTDouble()) {
 403                 double[] res = doubleArrayValue();
 404                 StringBuffer buf = new StringBuffer();
 405                 buf.append('[');
 406                 for (int i = 0; i < res.length; i++) {
 407                     buf.append(Double.toString(res[i]));
 408                     buf.append(", ");
 409                 }
 410                 buf.append(']');
 411                 str = buf.toString();
 412             } else {
 413                 str = "<unknown vector value>";
 414             }
 415         }
 416 
 417         // add units
 418         switch (dataUnits()) {
 419         case PerfDataUnits.U_None:
 420             break;
 421         case PerfDataUnits.U_Bytes:
 422             str += " byte(s)";
 423             break;
 424         case PerfDataUnits.U_Ticks:
 425             str += " tick(s)";
 426             break;
 427         case PerfDataUnits.U_Events:
 428             str += " event(s)";
 429             break;
 430         case PerfDataUnits.U_String:
 431             break;
 432         case PerfDataUnits.U_Hertz:
 433             str += " Hz";
 434             break;
 435         }
 436 
 437         return str;
 438     }
 439 
 440     // -- Internals only below this point
 441     private ObjectHeap getHeap() {
 442         return VM.getVM().getObjectHeap();
 443     }
 444 }