< prev index next >

core/org.openjdk.jmc.flightrecorder/src/main/java/org/openjdk/jmc/flightrecorder/parser/synthetic/SettingsTransformer.java

Print this page




  36 import static org.openjdk.jmc.common.unit.UnitLookup.FLAG;
  37 import static org.openjdk.jmc.common.unit.UnitLookup.TIMESPAN;
  38 
  39 import java.util.ArrayList;
  40 import java.util.Arrays;
  41 import java.util.HashMap;
  42 import java.util.List;
  43 import java.util.Map;
  44 
  45 import org.openjdk.jmc.common.item.IAttribute;
  46 import org.openjdk.jmc.common.unit.IQuantity;
  47 import org.openjdk.jmc.common.util.LabeledIdentifier;
  48 import org.openjdk.jmc.flightrecorder.JfrAttributes;
  49 import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
  50 import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
  51 import org.openjdk.jmc.flightrecorder.parser.IEventSink;
  52 import org.openjdk.jmc.flightrecorder.parser.IEventSinkFactory;
  53 import org.openjdk.jmc.flightrecorder.parser.ValueField;
  54 
  55 /**
  56  * Event sink that transforms pre JDK 9 event types to their equivalent JDK 9 types. JDK 9 input
  57  * data will be passed through mostly untouched.
  58  */
  59 class SettingsTransformer implements IEventSink {
  60 
  61         /**
  62          * Fix for JDK-8157024, the code cache stats unallocatedCapacity event is written as KiB but
  63          * reported as B. This is fixed in JDK9, but we need to perform this transformation for
  64          * recordings from JDK8 and earlier.
  65          */
  66         private static class FixCodeCacheSink implements IEventSink {
  67 
  68                 private int unallocatedFieldIndex;
  69                 private IEventSink subSink;
  70 
  71                 public FixCodeCacheSink(int unallocatedFieldIndex, IEventSink subSink) {
  72                         this.unallocatedFieldIndex = unallocatedFieldIndex;
  73                         this.subSink = subSink;
  74                 }
  75 
  76                 @Override


  86         // TODO: Break out constants?
  87         static final String REC_SETTING_NAME_ENABLED = "enabled"; //$NON-NLS-1$
  88         static final String REC_SETTING_NAME_STACKTRACE = "stacktrace"; //$NON-NLS-1$
  89         static final String REC_SETTING_NAME_THRESHOLD = "threshold"; //$NON-NLS-1$
  90         static final String REC_SETTING_NAME_PERIOD = "period"; //$NON-NLS-1$
  91 
  92         static final String REC_SETTING_PERIOD_EVERY_CHUNK = "everyChunk"; //$NON-NLS-1$
  93 
  94         private static final IAttribute<Boolean> REC_SETTINGS_ATTR_ENABLED = attr("enabled", //$NON-NLS-1$
  95                         Messages.getString(Messages.SettingsTransformer_REC_SETTINGS_ATTR_ENABLED), FLAG);
  96         private static final IAttribute<Boolean> REC_SETTINGS_ATTR_STACKTRACE = attr("stacktrace", //$NON-NLS-1$
  97                         Messages.getString(Messages.SettingsTransformer_REC_SETTINGS_ATTR_STACKTRACE), FLAG);
  98         static final IAttribute<IQuantity> REC_SETTINGS_ATTR_THRESHOLD = attr("threshold", //$NON-NLS-1$
  99                         Messages.getString(Messages.SettingsTransformer_REC_SETTINGS_ATTR_THRESHOLD), TIMESPAN);
 100         static final IAttribute<IQuantity> REC_SETTINGS_ATTR_PERIOD = attr("period", //$NON-NLS-1$
 101                         Messages.getString(Messages.SettingsTransformer_REC_SETTINGS_ATTR_PERIOD), TIMESPAN);
 102         private static final List<ValueField> FIELDS = Arrays.asList(new ValueField(JfrAttributes.END_TIME),
 103                         new ValueField(SyntheticAttributeExtension.REC_SETTING_EVENT_ID_ATTRIBUTE),
 104                         new ValueField(JdkAttributes.REC_SETTING_NAME), new ValueField(JdkAttributes.REC_SETTING_VALUE));
 105 
 106         // Renamed attributes from pre JDK 9: <event id, <pre 9 attribute id, 9 attribute id>>
 107         private static final Map<String, Map<String, String>> attributeRenameMap;
 108 
 109         // JDK-8157024 constant for the field id
 110         private static final String UNALLOCATED_CAPACITY_FIELD_ID = "unallocatedCapacity"; //$NON-NLS-1$
 111 
 112         private final IEventSink sink;
 113         private final Object[] reusableArray = new Object[FIELDS.size()];
 114         private int endTimeIndex = -1;
 115         private int typeIndex = -1;
 116         private int enabledIndex = -1;
 117         private int stacktraceIndex = -1;
 118         private int thresholdIndex = -1;
 119         private int periodIndex = -1;
 120 
 121         static {
 122                 attributeRenameMap = buildRenameMap();
 123         }
 124 
 125         @SuppressWarnings("nls")
 126         private static HashMap<String, Map<String, String>> buildRenameMap() {


 197                 if (endTimeIndex >= 0) {
 198                         sink = sinkFactory.create(JdkTypeIDs.RECORDING_SETTING, label, category, description, FIELDS);
 199                 } else {
 200                         sink = sinkFactory.create(JdkTypeIDs.RECORDING_SETTING, label, category, description, dataStructure);
 201                 }
 202         }
 203 
 204         boolean isValid() {
 205                 return endTimeIndex >= 0 && typeIndex >= 0 && enabledIndex >= 0 && stacktraceIndex >= 0 && thresholdIndex >= 0
 206                                 && periodIndex >= 0;
 207         }
 208 
 209         boolean isValidV1() {
 210                 return typeIndex >= 0;
 211         }
 212 
 213         @Override
 214         public void addEvent(Object[] values) {
 215                 LabeledIdentifier type = (LabeledIdentifier) values[typeIndex];
 216                 if (type != null) {
 217                         if (JdkTypeIDsPreJdk11.needTransform(type.getInterfaceId())) {
 218                                 type = new LabeledIdentifier(JdkTypeIDsPreJdk11.translate(type.getInterfaceId()),
 219                                                 type.getImplementationId(), type.getName(), type.getDeclaredDescription());
 220                         }
 221                         if (endTimeIndex < 0) {
 222                                 values[typeIndex] = type;
 223                                 sink.addEvent(values);
 224                                 return;
 225                         }
 226                 }
 227                 Object startTime = values[endTimeIndex];
 228 
 229                 addSettingEvent(startTime, type, REC_SETTING_NAME_ENABLED, values[enabledIndex]);
 230                 addSettingEvent(startTime, type, REC_SETTING_NAME_STACKTRACE, values[stacktraceIndex]);
 231                 addThresholdSettingEvent(startTime, type, (IQuantity) values[thresholdIndex]);
 232                 addPeriodSettingEvent(startTime, type, (IQuantity) values[periodIndex]);
 233         }
 234 
 235         private boolean addThresholdSettingEvent(Object startTime, LabeledIdentifier type, IQuantity quantity) {
 236                 // Remove thresholds with Long.MIN_VALUE ns duration as these are just padding for
 237                 // event types that cannot have thresholds. (At least JDK 7u75 used Long.MAX_VALUE.)
 238                 if (quantity != null) {
 239                         long numQuantity = quantity.longValue();
 240                         if ((numQuantity != Long.MIN_VALUE) && (numQuantity != Long.MAX_VALUE)) {


 263                 reusableArray[1] = type;
 264                 reusableArray[2] = settingName;
 265                 reusableArray[3] = settingValue == null ? null : settingValue.toString();
 266                 sink.addEvent(reusableArray);
 267         }
 268 
 269         /*
 270          * FIXME: Weird to explicitly wrap when the parser does exactly that.
 271          *
 272          * This class should be refactored into a parser extension although this may require a change to
 273          * the API by adding priorities so that type transformation occurs before synthetic attributes
 274          * are added.
 275          */
 276         static IEventSinkFactory wrapSinkFactory(final IEventSinkFactory subFactory) {
 277                 return new IEventSinkFactory() {
 278 
 279                         @Override
 280                         public IEventSink create(
 281                                 String identifier, String label, String[] category, String description,
 282                                 List<ValueField> dataStructure) {
 283                                 boolean needsTransform = JdkTypeIDsPreJdk11.needTransform(identifier);
 284                                 if (JdkTypeIDsPreJdk11.RECORDING_SETTING.equals(identifier) ||
 285                                                 (needsTransform &&
 286                                                                 JdkTypeIDs.RECORDING_SETTING.equals(JdkTypeIDsPreJdk11.translate(identifier)))) {
 287                                         SettingsTransformer st = new SettingsTransformer(subFactory, label, category, description,
 288                                                         dataStructure);
 289                                         if (st.isValid() || (needsTransform && st.isValidV1())) {
 290                                                 return st;
 291                                         } else {
 292                                                 // FIXME: Avoid System.err.println
 293                                                 System.err
 294                                                                 .println("Cannot create SettingsTransformer from fields: " + dataStructure.toString()); //$NON-NLS-1$
 295                                         }
 296                                 } else if (JdkTypeIDsPreJdk11.RECORDINGS.equals(identifier)) {
 297                                         /*
 298                                          * NOTE: Renaming 'duration' and 'startTime' attributes for JDK 8 'Recording'
 299                                          * events so that they won't conflict with general attributes with the same
 300                                          * names in JDK 9+ recordings.
 301                                          */
 302                                         ValueField[] struct = new ValueField[dataStructure.size()];
 303                                         for (int i = 0; i < struct.length; i++) {
 304                                                 ValueField vf = dataStructure.get(i);
 305                                                 if (vf.matches(JfrAttributes.START_TIME)) {
 306                                                         vf = new ValueField(JdkAttributes.RECORDING_START);
 307                                                 } else if (vf.matches(JfrAttributes.DURATION)) {
 308                                                         vf = new ValueField(JdkAttributes.RECORDING_DURATION);
 309                                                 }




  36 import static org.openjdk.jmc.common.unit.UnitLookup.FLAG;
  37 import static org.openjdk.jmc.common.unit.UnitLookup.TIMESPAN;
  38 
  39 import java.util.ArrayList;
  40 import java.util.Arrays;
  41 import java.util.HashMap;
  42 import java.util.List;
  43 import java.util.Map;
  44 
  45 import org.openjdk.jmc.common.item.IAttribute;
  46 import org.openjdk.jmc.common.unit.IQuantity;
  47 import org.openjdk.jmc.common.util.LabeledIdentifier;
  48 import org.openjdk.jmc.flightrecorder.JfrAttributes;
  49 import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
  50 import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
  51 import org.openjdk.jmc.flightrecorder.parser.IEventSink;
  52 import org.openjdk.jmc.flightrecorder.parser.IEventSinkFactory;
  53 import org.openjdk.jmc.flightrecorder.parser.ValueField;
  54 
  55 /**
  56  * Event sink that transforms pre JDK 11 event types to their equivalent JDK 11 types. JDK 11 input
  57  * data will be passed through mostly untouched.
  58  */
  59 class SettingsTransformer implements IEventSink {
  60 
  61         /**
  62          * Fix for JDK-8157024, the code cache stats unallocatedCapacity event is written as KiB but
  63          * reported as B. This is fixed in JDK9, but we need to perform this transformation for
  64          * recordings from JDK8 and earlier.
  65          */
  66         private static class FixCodeCacheSink implements IEventSink {
  67 
  68                 private int unallocatedFieldIndex;
  69                 private IEventSink subSink;
  70 
  71                 public FixCodeCacheSink(int unallocatedFieldIndex, IEventSink subSink) {
  72                         this.unallocatedFieldIndex = unallocatedFieldIndex;
  73                         this.subSink = subSink;
  74                 }
  75 
  76                 @Override


  86         // TODO: Break out constants?
  87         static final String REC_SETTING_NAME_ENABLED = "enabled"; //$NON-NLS-1$
  88         static final String REC_SETTING_NAME_STACKTRACE = "stacktrace"; //$NON-NLS-1$
  89         static final String REC_SETTING_NAME_THRESHOLD = "threshold"; //$NON-NLS-1$
  90         static final String REC_SETTING_NAME_PERIOD = "period"; //$NON-NLS-1$
  91 
  92         static final String REC_SETTING_PERIOD_EVERY_CHUNK = "everyChunk"; //$NON-NLS-1$
  93 
  94         private static final IAttribute<Boolean> REC_SETTINGS_ATTR_ENABLED = attr("enabled", //$NON-NLS-1$
  95                         Messages.getString(Messages.SettingsTransformer_REC_SETTINGS_ATTR_ENABLED), FLAG);
  96         private static final IAttribute<Boolean> REC_SETTINGS_ATTR_STACKTRACE = attr("stacktrace", //$NON-NLS-1$
  97                         Messages.getString(Messages.SettingsTransformer_REC_SETTINGS_ATTR_STACKTRACE), FLAG);
  98         static final IAttribute<IQuantity> REC_SETTINGS_ATTR_THRESHOLD = attr("threshold", //$NON-NLS-1$
  99                         Messages.getString(Messages.SettingsTransformer_REC_SETTINGS_ATTR_THRESHOLD), TIMESPAN);
 100         static final IAttribute<IQuantity> REC_SETTINGS_ATTR_PERIOD = attr("period", //$NON-NLS-1$
 101                         Messages.getString(Messages.SettingsTransformer_REC_SETTINGS_ATTR_PERIOD), TIMESPAN);
 102         private static final List<ValueField> FIELDS = Arrays.asList(new ValueField(JfrAttributes.END_TIME),
 103                         new ValueField(SyntheticAttributeExtension.REC_SETTING_EVENT_ID_ATTRIBUTE),
 104                         new ValueField(JdkAttributes.REC_SETTING_NAME), new ValueField(JdkAttributes.REC_SETTING_VALUE));
 105 
 106         // Renamed attributes from pre JDK 11: <event id, <pre 11 attribute id, 11 attribute id>>
 107         private static final Map<String, Map<String, String>> attributeRenameMap;
 108 
 109         // JDK-8157024 constant for the field id
 110         private static final String UNALLOCATED_CAPACITY_FIELD_ID = "unallocatedCapacity"; //$NON-NLS-1$
 111 
 112         private final IEventSink sink;
 113         private final Object[] reusableArray = new Object[FIELDS.size()];
 114         private int endTimeIndex = -1;
 115         private int typeIndex = -1;
 116         private int enabledIndex = -1;
 117         private int stacktraceIndex = -1;
 118         private int thresholdIndex = -1;
 119         private int periodIndex = -1;
 120 
 121         static {
 122                 attributeRenameMap = buildRenameMap();
 123         }
 124 
 125         @SuppressWarnings("nls")
 126         private static HashMap<String, Map<String, String>> buildRenameMap() {


 197                 if (endTimeIndex >= 0) {
 198                         sink = sinkFactory.create(JdkTypeIDs.RECORDING_SETTING, label, category, description, FIELDS);
 199                 } else {
 200                         sink = sinkFactory.create(JdkTypeIDs.RECORDING_SETTING, label, category, description, dataStructure);
 201                 }
 202         }
 203 
 204         boolean isValid() {
 205                 return endTimeIndex >= 0 && typeIndex >= 0 && enabledIndex >= 0 && stacktraceIndex >= 0 && thresholdIndex >= 0
 206                                 && periodIndex >= 0;
 207         }
 208 
 209         boolean isValidV1() {
 210                 return typeIndex >= 0;
 211         }
 212 
 213         @Override
 214         public void addEvent(Object[] values) {
 215                 LabeledIdentifier type = (LabeledIdentifier) values[typeIndex];
 216                 if (type != null) {

 217                         type = new LabeledIdentifier(JdkTypeIDsPreJdk11.translate(type.getInterfaceId()),
 218                                 type.getImplementationId(), type.getName(), type.getDeclaredDescription());

 219                         if (endTimeIndex < 0) {
 220                                 values[typeIndex] = type;
 221                                 sink.addEvent(values);
 222                                 return;
 223                         }
 224                 }
 225                 Object startTime = values[endTimeIndex];
 226 
 227                 addSettingEvent(startTime, type, REC_SETTING_NAME_ENABLED, values[enabledIndex]);
 228                 addSettingEvent(startTime, type, REC_SETTING_NAME_STACKTRACE, values[stacktraceIndex]);
 229                 addThresholdSettingEvent(startTime, type, (IQuantity) values[thresholdIndex]);
 230                 addPeriodSettingEvent(startTime, type, (IQuantity) values[periodIndex]);
 231         }
 232 
 233         private boolean addThresholdSettingEvent(Object startTime, LabeledIdentifier type, IQuantity quantity) {
 234                 // Remove thresholds with Long.MIN_VALUE ns duration as these are just padding for
 235                 // event types that cannot have thresholds. (At least JDK 7u75 used Long.MAX_VALUE.)
 236                 if (quantity != null) {
 237                         long numQuantity = quantity.longValue();
 238                         if ((numQuantity != Long.MIN_VALUE) && (numQuantity != Long.MAX_VALUE)) {


 261                 reusableArray[1] = type;
 262                 reusableArray[2] = settingName;
 263                 reusableArray[3] = settingValue == null ? null : settingValue.toString();
 264                 sink.addEvent(reusableArray);
 265         }
 266 
 267         /*
 268          * FIXME: Weird to explicitly wrap when the parser does exactly that.
 269          *
 270          * This class should be refactored into a parser extension although this may require a change to
 271          * the API by adding priorities so that type transformation occurs before synthetic attributes
 272          * are added.
 273          */
 274         static IEventSinkFactory wrapSinkFactory(final IEventSinkFactory subFactory) {
 275                 return new IEventSinkFactory() {
 276 
 277                         @Override
 278                         public IEventSink create(
 279                                 String identifier, String label, String[] category, String description,
 280                                 List<ValueField> dataStructure) {

 281                                 if (JdkTypeIDsPreJdk11.RECORDING_SETTING.equals(identifier) ||
 282                                         JdkTypeIDsPreJdk11.JDK9_RECORDING_SETTING.equals(identifier)) {

 283                                         SettingsTransformer st = new SettingsTransformer(subFactory, label, category, description,
 284                                                         dataStructure);
 285                                         if (st.isValid() || st.isValidV1()) {
 286                                                 return st;
 287                                         } else {
 288                                                 // FIXME: Avoid System.err.println
 289                                                 System.err
 290                                                                 .println("Cannot create SettingsTransformer from fields: " + dataStructure.toString()); //$NON-NLS-1$
 291                                         }
 292                                 } else if (JdkTypeIDsPreJdk11.RECORDINGS.equals(identifier)) {
 293                                         /*
 294                                          * NOTE: Renaming 'duration' and 'startTime' attributes for JDK 8 'Recording'
 295                                          * events so that they won't conflict with general attributes with the same
 296                                          * names in JDK 9+ recordings.
 297                                          */
 298                                         ValueField[] struct = new ValueField[dataStructure.size()];
 299                                         for (int i = 0; i < struct.length; i++) {
 300                                                 ValueField vf = dataStructure.get(i);
 301                                                 if (vf.matches(JfrAttributes.START_TIME)) {
 302                                                         vf = new ValueField(JdkAttributes.RECORDING_START);
 303                                                 } else if (vf.matches(JfrAttributes.DURATION)) {
 304                                                         vf = new ValueField(JdkAttributes.RECORDING_DURATION);
 305                                                 }


< prev index next >