src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriter.java
changeset 50113 caf115bb98ad
child 57360 5d043a159d5c
child 58863 c16ac7a2eba4
equal deleted inserted replaced
50112:7a2a740815b7 50113:caf115bb98ad
       
     1 /*
       
     2  * Copyright (c) 2016, 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.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package jdk.jfr.internal;
       
    27 
       
    28 import jdk.internal.misc.Unsafe;
       
    29 import jdk.jfr.internal.consumer.RecordingInput;
       
    30 
       
    31 /**
       
    32  * Class must reside in a package with package restriction.
       
    33  *
       
    34  * Users should not have direct access to underlying memory.
       
    35  *
       
    36  */
       
    37 public final class EventWriter {
       
    38     private static final Unsafe unsafe = Unsafe.getUnsafe();
       
    39     private final static JVM jvm = JVM.getJVM();
       
    40 
       
    41     private long startPosition;
       
    42     private long startPositionAddress;
       
    43     private long currentPosition;
       
    44     private long maxPosition;
       
    45     private final long threadID;
       
    46     private PlatformEventType eventType;
       
    47     private int maxEventSize;
       
    48     private boolean started;
       
    49     private boolean valid;
       
    50     private boolean flushOnEnd;
       
    51     // set by the JVM, not private to avoid being optimized out
       
    52     boolean notified;
       
    53 
       
    54     public static EventWriter getEventWriter() {
       
    55         EventWriter ew = (EventWriter)JVM.getEventWriter();
       
    56         return ew != null ? ew : JVM.newEventWriter();
       
    57     }
       
    58 
       
    59     public void putBoolean(boolean i) {
       
    60         if (isValidForSize(Byte.BYTES)) {
       
    61             currentPosition += Bits.putBoolean(currentPosition, i);
       
    62         }
       
    63     }
       
    64 
       
    65     public void putByte(byte i) {
       
    66         if (isValidForSize(Byte.BYTES)) {
       
    67             unsafe.putByte(currentPosition, i);
       
    68             ++currentPosition;
       
    69         }
       
    70     }
       
    71 
       
    72     public void putChar(char v) {
       
    73         if (isValidForSize(Character.BYTES + 1)) {
       
    74             putUncheckedLong(v);
       
    75         }
       
    76     }
       
    77 
       
    78     private void putUncheckedChar(char v) {
       
    79         putUncheckedLong(v);
       
    80     }
       
    81 
       
    82     public void putShort(short v) {
       
    83         if (isValidForSize(Short.BYTES + 1)) {
       
    84             putUncheckedLong(v & 0xFFFF);
       
    85         }
       
    86     }
       
    87 
       
    88     public void putInt(int v) {
       
    89         if (isValidForSize(Integer.BYTES + 1)) {
       
    90             putUncheckedLong(v & 0x00000000ffffffffL);
       
    91         }
       
    92     }
       
    93 
       
    94     private void putUncheckedInt(int v) {
       
    95         putUncheckedLong(v & 0x00000000ffffffffL);
       
    96     }
       
    97 
       
    98     public void putFloat(float i) {
       
    99         if (isValidForSize(Float.BYTES)) {
       
   100             currentPosition += Bits.putFloat(currentPosition, i);
       
   101         }
       
   102     }
       
   103 
       
   104     public void putLong(long v) {
       
   105         if (isValidForSize(Long.BYTES + 1)) {
       
   106             putUncheckedLong(v);
       
   107         }
       
   108     }
       
   109 
       
   110     public void putDouble(double i) {
       
   111         if (isValidForSize(Double.BYTES)) {
       
   112             currentPosition += Bits.putDouble(currentPosition, i);
       
   113         }
       
   114     }
       
   115 
       
   116     public void putString(String s, StringPool pool) {
       
   117         if (s == null) {
       
   118             putByte(RecordingInput.STRING_ENCODING_NULL);
       
   119             return;
       
   120         }
       
   121         int length = s.length();
       
   122         if (length == 0) {
       
   123             putByte(RecordingInput.STRING_ENCODING_EMPTY_STRING);
       
   124             return;
       
   125         }
       
   126         if (length > StringPool.MIN_LIMIT && length < StringPool.MAX_LIMIT) {
       
   127             long l = StringPool.addString(s);
       
   128             if (l > 0) {
       
   129                 putByte(RecordingInput.STRING_ENCODING_CONSTANT_POOL);
       
   130                 putLong(l);
       
   131                 return;
       
   132             }
       
   133         }
       
   134         putStringValue(s);
       
   135         return;
       
   136     }
       
   137 
       
   138     private void putStringValue(String s) {
       
   139         int length = s.length();
       
   140         if (isValidForSize(1 + 5 + 3 * length)) {
       
   141             putUncheckedByte(RecordingInput.STRING_ENCODING_CHAR_ARRAY); // 1 byte
       
   142             putUncheckedInt(length); // max 5 bytes
       
   143             for (int i = 0; i < length; i++) {
       
   144                 putUncheckedChar(s.charAt(i)); // max 3 bytes
       
   145             }
       
   146         }
       
   147     }
       
   148 
       
   149     public void putEventThread() {
       
   150         putLong(threadID);
       
   151     }
       
   152 
       
   153     public void putThread(Thread athread) {
       
   154         if (athread == null) {
       
   155             putLong(0L);
       
   156         } else {
       
   157             putLong(jvm.getThreadId(athread));
       
   158         }
       
   159     }
       
   160 
       
   161     public void putClass(Class<?> aClass) {
       
   162         if (aClass == null) {
       
   163             putLong(0L);
       
   164         } else {
       
   165             putLong(JVM.getClassIdNonIntrinsic(aClass));
       
   166         }
       
   167     }
       
   168 
       
   169     public void putStackTrace() {
       
   170         if (eventType.getStackTraceEnabled()) {
       
   171             putLong(jvm.getStackTraceId(eventType.getStackTraceOffset()));
       
   172         } else {
       
   173             putLong(0L);
       
   174         }
       
   175     }
       
   176 
       
   177     private void reserveEventSizeField() {
       
   178         // move currentPosition Integer.Bytes offset from start position
       
   179         if (isValidForSize(Integer.BYTES)) {
       
   180             currentPosition += Integer.BYTES;
       
   181         }
       
   182     }
       
   183 
       
   184     private void reset() {
       
   185         currentPosition = startPosition;
       
   186         if (flushOnEnd) {
       
   187             flushOnEnd = flush();
       
   188         }
       
   189         valid = true;
       
   190         started = false;
       
   191     }
       
   192 
       
   193     private boolean isValidForSize(int requestedSize) {
       
   194         if (!valid) {
       
   195             return false;
       
   196         }
       
   197         if (currentPosition + requestedSize > maxPosition) {
       
   198             flushOnEnd = flush(usedSize(), requestedSize);
       
   199             // retry
       
   200             if (currentPosition + requestedSize > maxPosition) {
       
   201                 Logger.log(LogTag.JFR_SYSTEM,
       
   202                            LogLevel.WARN, () ->
       
   203                                "Unable to commit. Requested size " + requestedSize + " too large");
       
   204                 valid = false;
       
   205                 return false;
       
   206             }
       
   207         }
       
   208         return true;
       
   209     }
       
   210 
       
   211     private boolean isNotified() {
       
   212         return notified;
       
   213     }
       
   214 
       
   215     private void resetNotified() {
       
   216         notified = false;
       
   217     }
       
   218 
       
   219     private int usedSize() {
       
   220         return (int) (currentPosition - startPosition);
       
   221     }
       
   222 
       
   223     private boolean flush() {
       
   224         return flush(usedSize(), 0);
       
   225     }
       
   226 
       
   227     private boolean flush(int usedSize, int requestedSize) {
       
   228         return JVM.flush(this, usedSize, requestedSize);
       
   229     }
       
   230 
       
   231     public boolean beginEvent(PlatformEventType eventType) {
       
   232         if (started) {
       
   233             // recursive write attempt
       
   234             return false;
       
   235         }
       
   236         started = true;
       
   237         this.eventType = eventType;
       
   238         reserveEventSizeField();
       
   239         putLong(eventType.getId());
       
   240         return true;
       
   241     }
       
   242 
       
   243     public boolean endEvent() {
       
   244         if (!valid) {
       
   245             reset();
       
   246             return true;
       
   247         }
       
   248         final int eventSize = usedSize();
       
   249         if (eventSize > maxEventSize) {
       
   250             reset();
       
   251             return true;
       
   252         }
       
   253         Bits.putInt(startPosition, makePaddedInt(eventSize));
       
   254         if (isNotified()) {
       
   255             resetNotified();
       
   256             reset();
       
   257             // returning false will trigger restart of the event write attempt
       
   258             return false;
       
   259         }
       
   260         startPosition = currentPosition;
       
   261         unsafe.putAddress(startPositionAddress, startPosition);
       
   262         // the event is now committed
       
   263         if (flushOnEnd) {
       
   264             flushOnEnd = flush();
       
   265         }
       
   266         started = false;
       
   267         return true;
       
   268     }
       
   269 
       
   270     private EventWriter(long startPos, long maxPos, long startPosAddress, long threadID, boolean valid) {
       
   271         startPosition = currentPosition = startPos;
       
   272         maxPosition = maxPos;
       
   273         startPositionAddress = startPosAddress;
       
   274         this.threadID = threadID;
       
   275         started = false;
       
   276         flushOnEnd = false;
       
   277         this.valid = valid;
       
   278         notified = false;
       
   279         // event may not exceed size for a padded integer
       
   280         maxEventSize = (1 << 28) -1;
       
   281     }
       
   282 
       
   283     private static int makePaddedInt(int v) {
       
   284         // bit  0-6 + pad => bit 24 - 31
       
   285         long b1 = (((v >>> 0) & 0x7F) | 0x80) << 24;
       
   286 
       
   287         // bit  7-13 + pad => bit 16 - 23
       
   288         long b2 = (((v >>> 7) & 0x7F) | 0x80) << 16;
       
   289 
       
   290         // bit 14-20 + pad => bit  8 - 15
       
   291         long b3 = (((v >>> 14) & 0x7F) | 0x80) << 8;
       
   292 
       
   293         // bit 21-28       => bit  0 -  7
       
   294         long b4 = (((v >>> 21) & 0x7F)) << 0;
       
   295 
       
   296         return (int) (b1 + b2 + b3 + b4);
       
   297     }
       
   298 
       
   299     private void putUncheckedLong(long v) {
       
   300         if ((v & ~0x7FL) == 0L) {
       
   301             putUncheckedByte((byte) v); // 0-6
       
   302             return;
       
   303         }
       
   304         putUncheckedByte((byte) (v | 0x80L)); // 0-6
       
   305         v >>>= 7;
       
   306         if ((v & ~0x7FL) == 0L) {
       
   307             putUncheckedByte((byte) v); // 7-13
       
   308             return;
       
   309         }
       
   310         putUncheckedByte((byte) (v | 0x80L)); // 7-13
       
   311         v >>>= 7;
       
   312         if ((v & ~0x7FL) == 0L) {
       
   313             putUncheckedByte((byte) v); // 14-20
       
   314             return;
       
   315         }
       
   316         putUncheckedByte((byte) (v | 0x80L)); // 14-20
       
   317         v >>>= 7;
       
   318         if ((v & ~0x7FL) == 0L) {
       
   319             putUncheckedByte((byte) v); // 21-27
       
   320             return;
       
   321         }
       
   322         putUncheckedByte((byte) (v | 0x80L)); // 21-27
       
   323         v >>>= 7;
       
   324         if ((v & ~0x7FL) == 0L) {
       
   325             putUncheckedByte((byte) v); // 28-34
       
   326             return;
       
   327         }
       
   328         putUncheckedByte((byte) (v | 0x80L)); // 28-34
       
   329         v >>>= 7;
       
   330         if ((v & ~0x7FL) == 0L) {
       
   331             putUncheckedByte((byte) v); // 35-41
       
   332             return;
       
   333         }
       
   334         putUncheckedByte((byte) (v | 0x80L)); // 35-41
       
   335         v >>>= 7;
       
   336         if ((v & ~0x7FL) == 0L) {
       
   337             putUncheckedByte((byte) v); // 42-48
       
   338             return;
       
   339         }
       
   340         putUncheckedByte((byte) (v | 0x80L)); // 42-48
       
   341         v >>>= 7;
       
   342 
       
   343         if ((v & ~0x7FL) == 0L) {
       
   344             putUncheckedByte((byte) v); // 49-55
       
   345             return;
       
   346         }
       
   347         putUncheckedByte((byte) (v | 0x80L)); // 49-55
       
   348         putUncheckedByte((byte) (v >>> 7)); // 56-63, last byte as is.
       
   349     }
       
   350 
       
   351     private void putUncheckedByte(byte i) {
       
   352         unsafe.putByte(currentPosition, i);
       
   353         ++currentPosition;
       
   354     }
       
   355 }