src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java
branchJEP-349-branch
changeset 57360 5d043a159d5c
parent 53014 339d2fbe8675
child 57470 025c9b8eaefd
equal deleted inserted replaced
57359:4cab5edc2950 57360:5d043a159d5c
     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;
    94         try {
    93         try {
    95             List<Timer> result = new CopyOnWriteArrayList<>();
    94             List<Timer> result = new CopyOnWriteArrayList<>();
    96             Thread t = SecuritySupport.createThreadWitNoPermissions("Permissionless thread", ()-> {
    95             Thread t = SecuritySupport.createThreadWitNoPermissions("Permissionless thread", ()-> {
    97                 result.add(new Timer("JFR Recording Scheduler", true));
    96                 result.add(new Timer("JFR Recording Scheduler", true));
    98             });
    97             });
       
    98             jvm.exclude(t);
    99             t.start();
    99             t.start();
   100             t.join();
   100             t.join();
   101             return result.get(0);
   101             return result.get(0);
   102         } catch (InterruptedException e) {
   102         } catch (InterruptedException e) {
   103             throw new IllegalStateException("Not able to create timer task. " + e.getMessage(), e);
   103             throw new IllegalStateException("Not able to create timer task. " + e.getMessage(), e);
   202             jvm.destroyNativeJFR();
   202             jvm.destroyNativeJFR();
   203         }
   203         }
   204         repository.clear();
   204         repository.clear();
   205     }
   205     }
   206 
   206 
   207     synchronized void start(PlatformRecording recording) {
   207     synchronized long start(PlatformRecording recording) {
   208         // State can only be NEW or DELAYED because of previous checks
   208         // State can only be NEW or DELAYED because of previous checks
   209         Instant now = Instant.now();
   209         Instant now = Instant.now();
   210         recording.setStartTime(now);
   210         recording.setStartTime(now);
   211         recording.updateTimer();
   211         recording.updateTimer();
   212         Duration duration = recording.getDuration();
   212         Duration duration = recording.getDuration();
   213         if (duration != null) {
   213         if (duration != null) {
   214             recording.setStopTime(now.plus(duration));
   214             recording.setStopTime(now.plus(duration));
   215         }
   215         }
   216         boolean toDisk = recording.isToDisk();
   216         boolean toDisk = recording.isToDisk();
   217         boolean beginPhysical = true;
   217         boolean beginPhysical = true;
       
   218         long streamInterval = recording.getStreamIntervalMillis();
   218         for (PlatformRecording s : getRecordings()) {
   219         for (PlatformRecording s : getRecordings()) {
   219             if (s.getState() == RecordingState.RUNNING) {
   220             if (s.getState() == RecordingState.RUNNING) {
   220                 beginPhysical = false;
   221                 beginPhysical = false;
   221                 if (s.isToDisk()) {
   222                 if (s.isToDisk()) {
   222                     toDisk = true;
   223                     toDisk = true;
   223                 }
   224                 }
   224             }
   225                 streamInterval = Math.min(streamInterval, s.getStreamIntervalMillis());
   225         }
   226             }
       
   227         }
       
   228         long startNanos = -1;
   226         if (beginPhysical) {
   229         if (beginPhysical) {
   227             RepositoryChunk newChunk = null;
   230             RepositoryChunk newChunk = null;
   228             if (toDisk) {
   231             if (toDisk) {
   229                 newChunk = repository.newChunk(now);
   232                 newChunk = repository.newChunk(now);
   230                 MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
   233                 MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
   231             } else {
   234             } else {
   232                 MetadataRepository.getInstance().setOutput(null);
   235                 MetadataRepository.getInstance().setOutput(null);
   233             }
   236             }
   234             currentChunk = newChunk;
   237             currentChunk = newChunk;
   235             jvm.beginRecording_();
   238             jvm.beginRecording_();
       
   239             startNanos = jvm.getChunkStartNanos();
   236             recording.setState(RecordingState.RUNNING);
   240             recording.setState(RecordingState.RUNNING);
   237             updateSettings();
   241             updateSettings();
   238             writeMetaEvents();
   242             writeMetaEvents();
   239         } else {
   243         } else {
   240             RepositoryChunk newChunk = null;
   244             RepositoryChunk newChunk = null;
   241             if (toDisk) {
   245             if (toDisk) {
   242                 newChunk = repository.newChunk(now);
   246                 newChunk = repository.newChunk(now);
   243                 RequestEngine.doChunkEnd();
   247                 RequestEngine.doChunkEnd();
   244                 MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
   248                 MetadataRepository.getInstance().setOutput(newChunk.getUnfishedFile().toString());
       
   249                 startNanos = jvm.getChunkStartNanos();
   245             }
   250             }
   246             recording.setState(RecordingState.RUNNING);
   251             recording.setState(RecordingState.RUNNING);
   247             updateSettings();
   252             updateSettings();
   248             writeMetaEvents();
   253             writeMetaEvents();
   249             if (currentChunk != null) {
   254             if (currentChunk != null) {
   250                 finishChunk(currentChunk, now, recording);
   255                 finishChunk(currentChunk, now, recording);
   251             }
   256             }
   252             currentChunk = newChunk;
   257             currentChunk = newChunk;
   253         }
   258         }
   254 
   259         if (toDisk) {
       
   260             RequestEngine.setFlushInterval(streamInterval);
       
   261         }
   255         RequestEngine.doChunkBegin();
   262         RequestEngine.doChunkBegin();
       
   263 
       
   264         return startNanos;
   256     }
   265     }
   257 
   266 
   258     synchronized void stop(PlatformRecording recording) {
   267     synchronized void stop(PlatformRecording recording) {
   259         RecordingState state = recording.getState();
   268         RecordingState state = recording.getState();
   260 
   269 
   265             throw new IllegalStateException("Recording must be started before it can be stopped.");
   274             throw new IllegalStateException("Recording must be started before it can be stopped.");
   266         }
   275         }
   267         Instant now = Instant.now();
   276         Instant now = Instant.now();
   268         boolean toDisk = false;
   277         boolean toDisk = false;
   269         boolean endPhysical = true;
   278         boolean endPhysical = true;
       
   279         long streamInterval = Long.MAX_VALUE;
   270         for (PlatformRecording s : getRecordings()) {
   280         for (PlatformRecording s : getRecordings()) {
   271             RecordingState rs = s.getState();
   281             RecordingState rs = s.getState();
   272             if (s != recording && RecordingState.RUNNING == rs) {
   282             if (s != recording && RecordingState.RUNNING == rs) {
   273                 endPhysical = false;
   283                 endPhysical = false;
   274                 if (s.isToDisk()) {
   284                 if (s.isToDisk()) {
   275                     toDisk = true;
   285                     toDisk = true;
   276                 }
   286                 }
       
   287                 streamInterval = Math.min(streamInterval, s.getStreamIntervalMillis());
   277             }
   288             }
   278         }
   289         }
   279         OldObjectSample.emit(recording);
   290         OldObjectSample.emit(recording);
   280 
   291 
   281         if (endPhysical) {
   292         if (endPhysical) {
   307                 finishChunk(currentChunk, now, null);
   318                 finishChunk(currentChunk, now, null);
   308             }
   319             }
   309             currentChunk = newChunk;
   320             currentChunk = newChunk;
   310             RequestEngine.doChunkBegin();
   321             RequestEngine.doChunkBegin();
   311         }
   322         }
       
   323 
       
   324         if (toDisk) {
       
   325             RequestEngine.setFlushInterval(streamInterval);
       
   326         } else {
       
   327             RequestEngine.setFlushInterval(Long.MAX_VALUE);
       
   328         }
       
   329 
   312         recording.setState(RecordingState.STOPPED);
   330         recording.setState(RecordingState.STOPPED);
   313     }
   331     }
   314 
   332 
   315     private void dumpMemoryToDestination(PlatformRecording recording)  {
   333     private void dumpMemoryToDestination(PlatformRecording recording)  {
   316         WriteableUserPath dest = recording.getDestination();
   334         WriteableUserPath dest = recording.getDestination();
   393         for (PlatformRecording r : getRecordings()) {
   411         for (PlatformRecording r : getRecordings()) {
   394             if (r != ignoreMe && r.getState() == RecordingState.RUNNING) {
   412             if (r != ignoreMe && r.getState() == RecordingState.RUNNING) {
   395                 r.appendChunk(chunk);
   413                 r.appendChunk(chunk);
   396             }
   414             }
   397         }
   415         }
       
   416         FilePurger.purge();
   398     }
   417     }
   399 
   418 
   400     private void writeMetaEvents() {
   419     private void writeMetaEvents() {
   401 
   420 
   402         if (activeRecordingEvent.isEnabled()) {
   421         if (activeRecordingEvent.isEnabled()) {
   413                     event.maxAge = age == null ? Long.MAX_VALUE : age.toMillis();
   432                     event.maxAge = age == null ? Long.MAX_VALUE : age.toMillis();
   414                     Long size = r.getMaxSize();
   433                     Long size = r.getMaxSize();
   415                     event.maxSize = size == null ? Long.MAX_VALUE : size;
   434                     event.maxSize = size == null ? Long.MAX_VALUE : size;
   416                     Instant start = r.getStartTime();
   435                     Instant start = r.getStartTime();
   417                     event.recordingStart = start == null ? Long.MAX_VALUE : start.toEpochMilli();
   436                     event.recordingStart = start == null ? Long.MAX_VALUE : start.toEpochMilli();
       
   437                     Duration fi = r.getFlushInterval();
       
   438                     event.flushInterval = fi == null ? Long.MAX_VALUE : fi.toMillis();
   418                     event.commit();
   439                     event.commit();
   419                 }
   440                 }
   420             }
   441             }
   421         }
   442         }
   422         if (activeSettingEvent.isEnabled()) {
   443         if (activeSettingEvent.isEnabled()) {
   446         try {
   467         try {
   447             synchronized (JVM.FILE_DELTA_CHANGE) {
   468             synchronized (JVM.FILE_DELTA_CHANGE) {
   448                 JVM.FILE_DELTA_CHANGE.wait(duration < 10 ? 10 : duration);
   469                 JVM.FILE_DELTA_CHANGE.wait(duration < 10 ? 10 : duration);
   449             }
   470             }
   450         } catch (InterruptedException e) {
   471         } catch (InterruptedException e) {
   451             e.printStackTrace();
   472             // Ignore
   452         }
   473         }
   453     }
   474     }
   454 
   475 
   455     synchronized Recording newCopy(PlatformRecording r, boolean stop) {
   476     synchronized Recording newCopy(PlatformRecording r, boolean stop) {
   456         Recording newRec = new Recording();
   477         Recording newRec = new Recording();