src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java
changeset 58863 c16ac7a2eba4
parent 55256 3b22c7e00573
child 59226 a0f39cc47387
equal deleted inserted replaced
58861:2c3cc4b01880 58863:c16ac7a2eba4
     1 /*
     1 /*
     2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    29 import static jdk.jfr.internal.LogLevel.TRACE;
    29 import static jdk.jfr.internal.LogLevel.TRACE;
    30 import static jdk.jfr.internal.LogLevel.WARN;
    30 import static jdk.jfr.internal.LogLevel.WARN;
    31 import static jdk.jfr.internal.LogTag.JFR;
    31 import static jdk.jfr.internal.LogTag.JFR;
    32 import static jdk.jfr.internal.LogTag.JFR_SYSTEM;
    32 import static jdk.jfr.internal.LogTag.JFR_SYSTEM;
    33 
    33 
    34 import java.io.IOException;
       
    35 import java.security.AccessControlContext;
    34 import java.security.AccessControlContext;
    36 import java.security.AccessController;
    35 import java.security.AccessController;
    37 import java.time.Duration;
    36 import java.time.Duration;
    38 import java.time.Instant;
    37 import java.time.Instant;
    39 import java.util.ArrayList;
    38 import java.util.ArrayList;
    56 import jdk.jfr.events.ActiveSettingEvent;
    55 import jdk.jfr.events.ActiveSettingEvent;
    57 import jdk.jfr.internal.SecuritySupport.SecureRecorderListener;
    56 import jdk.jfr.internal.SecuritySupport.SecureRecorderListener;
    58 import jdk.jfr.internal.instrument.JDKEvents;
    57 import jdk.jfr.internal.instrument.JDKEvents;
    59 
    58 
    60 public final class PlatformRecorder {
    59 public final class PlatformRecorder {
       
    60 
    61 
    61 
    62     private final List<PlatformRecording> recordings = new ArrayList<>();
    62     private final List<PlatformRecording> recordings = new ArrayList<>();
    63     private final static List<SecureRecorderListener> changeListeners = new ArrayList<>();
    63     private final static List<SecureRecorderListener> changeListeners = new ArrayList<>();
    64     private final Repository repository;
    64     private final Repository repository;
    65     private final Timer timer;
    65     private final Timer timer;
    94         try {
    94         try {
    95             List<Timer> result = new CopyOnWriteArrayList<>();
    95             List<Timer> result = new CopyOnWriteArrayList<>();
    96             Thread t = SecuritySupport.createThreadWitNoPermissions("Permissionless thread", ()-> {
    96             Thread t = SecuritySupport.createThreadWitNoPermissions("Permissionless thread", ()-> {
    97                 result.add(new Timer("JFR Recording Scheduler", true));
    97                 result.add(new Timer("JFR Recording Scheduler", true));
    98             });
    98             });
       
    99             jvm.exclude(t);
    99             t.start();
   100             t.start();
   100             t.join();
   101             t.join();
   101             return result.get(0);
   102             return result.get(0);
   102         } catch (InterruptedException e) {
   103         } catch (InterruptedException e) {
   103             throw new IllegalStateException("Not able to create timer task. " + e.getMessage(), e);
   104             throw new IllegalStateException("Not able to create timer task. " + e.getMessage(), e);
   202             jvm.destroyNativeJFR();
   203             jvm.destroyNativeJFR();
   203         }
   204         }
   204         repository.clear();
   205         repository.clear();
   205     }
   206     }
   206 
   207 
   207     synchronized void start(PlatformRecording recording) {
   208     synchronized long start(PlatformRecording recording) {
   208         // State can only be NEW or DELAYED because of previous checks
   209         // State can only be NEW or DELAYED because of previous checks
   209         Instant now = Instant.now();
   210         Instant now = Instant.now();
   210         recording.setStartTime(now);
   211         recording.setStartTime(now);
   211         recording.updateTimer();
   212         recording.updateTimer();
   212         Duration duration = recording.getDuration();
   213         Duration duration = recording.getDuration();
   213         if (duration != null) {
   214         if (duration != null) {
   214             recording.setStopTime(now.plus(duration));
   215             recording.setStopTime(now.plus(duration));
   215         }
   216         }
   216         boolean toDisk = recording.isToDisk();
   217         boolean toDisk = recording.isToDisk();
   217         boolean beginPhysical = true;
   218         boolean beginPhysical = true;
       
   219         long streamInterval = recording.getStreamIntervalMillis();
   218         for (PlatformRecording s : getRecordings()) {
   220         for (PlatformRecording s : getRecordings()) {
   219             if (s.getState() == RecordingState.RUNNING) {
   221             if (s.getState() == RecordingState.RUNNING) {
   220                 beginPhysical = false;
   222                 beginPhysical = false;
   221                 if (s.isToDisk()) {
   223                 if (s.isToDisk()) {
   222                     toDisk = true;
   224                     toDisk = true;
   223                 }
   225                 }
   224             }
   226                 streamInterval = Math.min(streamInterval, s.getStreamIntervalMillis());
   225         }
   227             }
       
   228         }
       
   229         long startNanos = -1;
   226         if (beginPhysical) {
   230         if (beginPhysical) {
   227             RepositoryChunk newChunk = null;
   231             RepositoryChunk newChunk = null;
   228             if (toDisk) {
   232             if (toDisk) {
   229                 newChunk = repository.newChunk(now);
   233                 newChunk = repository.newChunk(now);
   230                 MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
   234                 MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
   231             } else {
   235             } else {
   232                 MetadataRepository.getInstance().setOutput(null);
   236                 MetadataRepository.getInstance().setOutput(null);
   233             }
   237             }
   234             currentChunk = newChunk;
   238             currentChunk = newChunk;
   235             jvm.beginRecording_();
   239             jvm.beginRecording_();
       
   240             startNanos = jvm.getChunkStartNanos();
   236             recording.setState(RecordingState.RUNNING);
   241             recording.setState(RecordingState.RUNNING);
   237             updateSettings();
   242             updateSettings();
   238             writeMetaEvents();
   243             writeMetaEvents();
   239         } else {
   244         } else {
   240             RepositoryChunk newChunk = null;
   245             RepositoryChunk newChunk = null;
   241             if (toDisk) {
   246             if (toDisk) {
   242                 newChunk = repository.newChunk(now);
   247                 newChunk = repository.newChunk(now);
   243                 RequestEngine.doChunkEnd();
   248                 RequestEngine.doChunkEnd();
   244                 MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
   249                 MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
       
   250                 startNanos = jvm.getChunkStartNanos();
   245             }
   251             }
   246             recording.setState(RecordingState.RUNNING);
   252             recording.setState(RecordingState.RUNNING);
   247             updateSettings();
   253             updateSettings();
   248             writeMetaEvents();
   254             writeMetaEvents();
   249             if (currentChunk != null) {
   255             if (currentChunk != null) {
   250                 finishChunk(currentChunk, now, recording);
   256                 finishChunk(currentChunk, now, recording);
   251             }
   257             }
   252             currentChunk = newChunk;
   258             currentChunk = newChunk;
   253         }
   259         }
   254 
   260         if (toDisk) {
       
   261             RequestEngine.setFlushInterval(streamInterval);
       
   262         }
   255         RequestEngine.doChunkBegin();
   263         RequestEngine.doChunkBegin();
       
   264 
       
   265         return startNanos;
   256     }
   266     }
   257 
   267 
   258     synchronized void stop(PlatformRecording recording) {
   268     synchronized void stop(PlatformRecording recording) {
   259         RecordingState state = recording.getState();
   269         RecordingState state = recording.getState();
   260 
   270 
   265             throw new IllegalStateException("Recording must be started before it can be stopped.");
   275             throw new IllegalStateException("Recording must be started before it can be stopped.");
   266         }
   276         }
   267         Instant now = Instant.now();
   277         Instant now = Instant.now();
   268         boolean toDisk = false;
   278         boolean toDisk = false;
   269         boolean endPhysical = true;
   279         boolean endPhysical = true;
       
   280         long streamInterval = Long.MAX_VALUE;
   270         for (PlatformRecording s : getRecordings()) {
   281         for (PlatformRecording s : getRecordings()) {
   271             RecordingState rs = s.getState();
   282             RecordingState rs = s.getState();
   272             if (s != recording && RecordingState.RUNNING == rs) {
   283             if (s != recording && RecordingState.RUNNING == rs) {
   273                 endPhysical = false;
   284                 endPhysical = false;
   274                 if (s.isToDisk()) {
   285                 if (s.isToDisk()) {
   275                     toDisk = true;
   286                     toDisk = true;
   276                 }
   287                 }
       
   288                 streamInterval = Math.min(streamInterval, s.getStreamIntervalMillis());
   277             }
   289             }
   278         }
   290         }
   279         OldObjectSample.emit(recording);
   291         OldObjectSample.emit(recording);
   280 
   292 
   281         if (endPhysical) {
   293         if (endPhysical) {
   307                 finishChunk(currentChunk, now, null);
   319                 finishChunk(currentChunk, now, null);
   308             }
   320             }
   309             currentChunk = newChunk;
   321             currentChunk = newChunk;
   310             RequestEngine.doChunkBegin();
   322             RequestEngine.doChunkBegin();
   311         }
   323         }
       
   324 
       
   325         if (toDisk) {
       
   326             RequestEngine.setFlushInterval(streamInterval);
       
   327         } else {
       
   328             RequestEngine.setFlushInterval(Long.MAX_VALUE);
       
   329         }
       
   330 
   312         recording.setState(RecordingState.STOPPED);
   331         recording.setState(RecordingState.STOPPED);
   313     }
   332     }
   314 
   333 
   315     private void dumpMemoryToDestination(PlatformRecording recording)  {
   334     private void dumpMemoryToDestination(PlatformRecording recording)  {
   316         WriteableUserPath dest = recording.getDestination();
   335         WriteableUserPath dest = recording.getDestination();
   334             if (r != ignoreMe) {
   353             if (r != ignoreMe) {
   335                 list.add(r.getSettings());
   354                 list.add(r.getSettings());
   336             }
   355             }
   337         }
   356         }
   338         MetadataRepository.getInstance().setSettings(list);
   357         MetadataRepository.getInstance().setSettings(list);
       
   358     }
       
   359 
       
   360     public synchronized void rotateIfRecordingToDisk() {
       
   361         boolean disk = false;
       
   362         for (PlatformRecording s : getRecordings()) {
       
   363             if (RecordingState.RUNNING == s.getState() && s.isToDisk()) {
       
   364                 disk = true;
       
   365             }
       
   366         }
       
   367         if (disk) {
       
   368             rotateDisk();
       
   369         }
   339     }
   370     }
   340 
   371 
   341     synchronized void rotateDisk() {
   372     synchronized void rotateDisk() {
   342         Instant now = Instant.now();
   373         Instant now = Instant.now();
   343         RepositoryChunk newChunk = repository.newChunk(now);
   374         RepositoryChunk newChunk = repository.newChunk(now);
   393         for (PlatformRecording r : getRecordings()) {
   424         for (PlatformRecording r : getRecordings()) {
   394             if (r != ignoreMe && r.getState() == RecordingState.RUNNING) {
   425             if (r != ignoreMe && r.getState() == RecordingState.RUNNING) {
   395                 r.appendChunk(chunk);
   426                 r.appendChunk(chunk);
   396             }
   427             }
   397         }
   428         }
       
   429         FilePurger.purge();
   398     }
   430     }
   399 
   431 
   400     private void writeMetaEvents() {
   432     private void writeMetaEvents() {
   401 
       
   402         if (activeRecordingEvent.isEnabled()) {
   433         if (activeRecordingEvent.isEnabled()) {
       
   434             ActiveRecordingEvent event = ActiveRecordingEvent.EVENT.get();
   403             for (PlatformRecording r : getRecordings()) {
   435             for (PlatformRecording r : getRecordings()) {
   404                 if (r.getState() == RecordingState.RUNNING && r.shouldWriteMetadataEvent()) {
   436                 if (r.getState() == RecordingState.RUNNING && r.shouldWriteMetadataEvent()) {
   405                     ActiveRecordingEvent event = new ActiveRecordingEvent();
       
   406                     event.id = r.getId();
   437                     event.id = r.getId();
   407                     event.name = r.getName();
   438                     event.name = r.getName();
   408                     WriteableUserPath p = r.getDestination();
   439                     WriteableUserPath p = r.getDestination();
   409                     event.destination = p == null ? null : p.getRealPathText();
   440                     event.destination = p == null ? null : p.getRealPathText();
   410                     Duration d = r.getDuration();
   441                     Duration d = r.getDuration();
   413                     event.maxAge = age == null ? Long.MAX_VALUE : age.toMillis();
   444                     event.maxAge = age == null ? Long.MAX_VALUE : age.toMillis();
   414                     Long size = r.getMaxSize();
   445                     Long size = r.getMaxSize();
   415                     event.maxSize = size == null ? Long.MAX_VALUE : size;
   446                     event.maxSize = size == null ? Long.MAX_VALUE : size;
   416                     Instant start = r.getStartTime();
   447                     Instant start = r.getStartTime();
   417                     event.recordingStart = start == null ? Long.MAX_VALUE : start.toEpochMilli();
   448                     event.recordingStart = start == null ? Long.MAX_VALUE : start.toEpochMilli();
       
   449                     Duration fi = r.getFlushInterval();
       
   450                     event.flushInterval = fi == null ? Long.MAX_VALUE : fi.toMillis();
   418                     event.commit();
   451                     event.commit();
   419                 }
   452                 }
   420             }
   453             }
   421         }
   454         }
   422         if (activeSettingEvent.isEnabled()) {
   455         if (activeSettingEvent.isEnabled()) {
   446         try {
   479         try {
   447             synchronized (JVM.FILE_DELTA_CHANGE) {
   480             synchronized (JVM.FILE_DELTA_CHANGE) {
   448                 JVM.FILE_DELTA_CHANGE.wait(duration < 10 ? 10 : duration);
   481                 JVM.FILE_DELTA_CHANGE.wait(duration < 10 ? 10 : duration);
   449             }
   482             }
   450         } catch (InterruptedException e) {
   483         } catch (InterruptedException e) {
   451             e.printStackTrace();
   484             // Ignore
   452         }
   485         }
   453     }
   486     }
   454 
   487 
   455     synchronized Recording newCopy(PlatformRecording r, boolean stop) {
   488     synchronized Recording newCopy(PlatformRecording r, boolean stop) {
   456         Recording newRec = new Recording();
   489         Recording newRec = new Recording();
   548         }
   581         }
   549         target.setStartTime(startTime);
   582         target.setStartTime(startTime);
   550         target.setStopTime(endTime);
   583         target.setStopTime(endTime);
   551         target.setInternalDuration(Duration.between(startTime, endTime));
   584         target.setInternalDuration(Duration.between(startTime, endTime));
   552     }
   585     }
       
   586 
       
   587 
       
   588 
   553 }
   589 }