1 /*
2  * Copyright (c) 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.api.event;
27 
28 import java.time.Duration;
29 
30 import jdk.jfr.Event;
31 import jdk.jfr.Recording;
32 import jdk.test.lib.Asserts;
33 
34 /**
35  * @test
36  * @summary Test enable/disable event and verify recording has expected events.
37  * @key jfr
38  * @requires vm.hasJFR
39  * @library /test/lib
40  * @run main/othervm -Xlog:jfr+event+setting=trace jdk.jfr.api.event.TestShouldCommit
41  */
42 
43 public class TestShouldCommit {
44 
main(String[] args)45     public static void main(String[] args) throws Exception {
46         Recording rA = new Recording();
47 
48         verifyShouldCommitFalse(); // No active recordings
49 
50         rA.start();
51         rA.enable(MyEvent.class).withoutThreshold(); // recA=all
52         verifyShouldCommitTrue();
53 
54         setThreshold(rA, 100); // recA=100
55         verifyThreshold(100);
56 
57         setThreshold(rA, 200); // recA=200
58         verifyThreshold(200);
59 
60         Recording rB = new Recording();
61         verifyThreshold(200);  // recA=200, recB=not started
62 
63         rB.start();
64         verifyThreshold(200);  // recA=200, recB=not specified, settings from recA is used.
65 
66         setThreshold(rB, 100); // recA=200, recB=100
67         verifyThreshold(100);
68 
69         setThreshold(rB, 300); // recA=200, recB=300
70         verifyThreshold(200);
71 
72         rA.disable(MyEvent.class); // recA=disabled, recB=300
73 
74         verifyThreshold(300);
75 
76         rB.disable(MyEvent.class); // recA=disabled, recB=disabled
77         verifyShouldCommitFalse();
78 
79         setThreshold(rA, 200); // recA=200, recB=disabled
80         verifyThreshold(200);
81 
82         rB.enable(MyEvent.class).withoutThreshold(); // recA=200, recB=all
83         verifyShouldCommitTrue();
84 
85         setThreshold(rB, 100); // recA=200, recB=100
86         verifyThreshold(100);
87 
88         rB.stop(); // recA=200, recB=stopped
89         verifyThreshold(200);
90 
91         rA.stop(); // recA=stopped, recB=stopped
92         verifyShouldCommitFalse();
93 
94         rA.close();
95         rB.close();
96 
97         verifyShouldCommitFalse();
98     }
99 
setThreshold(Recording r, long millis)100     private static void setThreshold(Recording r, long millis) {
101         r.enable(MyEvent.class).withThreshold(Duration.ofMillis(millis));
102     }
103 
verifyThreshold(long threshold)104     private static void verifyThreshold(long threshold) throws Exception {
105         // Create 2 events, with different sleep time between begin() and end()
106         // First event ends just before threshold, the other just after.
107         verifyThreshold(threshold-5, threshold);
108         verifyThreshold(threshold+5, threshold);
109     }
110 
verifyThreshold(long sleepMs, long thresholdMs)111     private static void verifyThreshold(long sleepMs, long thresholdMs) throws Exception {
112         MyEvent event = new MyEvent();
113 
114         long beforeStartNanos = System.nanoTime();
115         event.begin();
116         long afterStartNanos = System.nanoTime();
117 
118         Thread.sleep(sleepMs);
119 
120         long beforeStopNanos = System.nanoTime();
121         event.end();
122         long afterStopNanos = System.nanoTime();
123 
124         boolean actualShouldCommit = event.shouldCommit();
125 
126         final long safetyMarginNanos = 2000000; // Allow an error of 2 ms. May have to be tuned.
127 
128         //Duration of event has been at least minDurationMicros
129         long minDurationMicros = (beforeStopNanos - afterStartNanos - safetyMarginNanos) / 1000;
130         //Duration of event has been at most maxDurationMicros
131         long maxDurationMicros = (afterStopNanos - beforeStartNanos + safetyMarginNanos) / 1000;
132         Asserts.assertLessThanOrEqual(minDurationMicros, maxDurationMicros, "Wrong min/max duration. Test error.");
133 
134         long thresholdMicros = thresholdMs * 1000;
135         Boolean shouldCommit = null;
136         if (minDurationMicros > thresholdMicros) {
137             shouldCommit = new Boolean(true);  // shouldCommit() must be true
138         } else if (maxDurationMicros < thresholdMicros) {
139             shouldCommit = new Boolean(false); // shouldCommit() must be false
140         } else {
141             // Too close to call. No checks are done since we are not sure of expected shouldCommit().
142         }
143 
144         System.out.printf(
145             "threshold=%d, duration=[%d-%d], shouldCommit()=%b, expected=%s%n",
146             thresholdMicros, minDurationMicros, maxDurationMicros, actualShouldCommit,
147             (shouldCommit!=null ? shouldCommit : "too close to call"));
148 
149         try {
150             if (shouldCommit != null) {
151                 Asserts.assertEquals(shouldCommit.booleanValue(), actualShouldCommit, "Wrong shouldCommit()");
152             }
153         } catch (Exception e) {
154             System.out.println("Unexpected value of shouldCommit(). Searching for active threshold...");
155             searchThreshold(thresholdMs, 2000+thresholdMs);
156             throw e;
157         }
158     }
159 
160     // Sleeps until shouldCommit() is true, or give up. Used for logging.
searchThreshold(long expectedMs, long maxMs)161     private static void searchThreshold(long expectedMs, long maxMs) throws Exception {
162         long start = System.nanoTime();
163         long stop = start + maxMs * 1000000;
164 
165         MyEvent event = new MyEvent();
166         event.begin();
167         event.end();
168 
169         while (!event.shouldCommit() && System.nanoTime() < stop) {
170             Thread.sleep(1);
171             event.end();
172         }
173         long durationMicros = (System.nanoTime() - start) / 1000;
174         long expectedMicros = expectedMs * 1000;
175         System.out.printf("shouldCommit()=%b after %,d ms, expected %,d%n", event.shouldCommit(), durationMicros, expectedMicros);
176     }
177 
verifyShouldCommitFalse()178     private static void verifyShouldCommitFalse() {
179         MyEvent event = new MyEvent();
180         event.begin();
181         event.end();
182         Asserts.assertFalse(event.shouldCommit(), "shouldCommit() expected false");
183     }
184 
verifyShouldCommitTrue()185     private static void verifyShouldCommitTrue() {
186         MyEvent event = new MyEvent();
187         event.begin();
188         event.end();
189         Asserts.assertTrue(event.shouldCommit(), "shouldCommit() expected true");
190     }
191 
192     private static class MyEvent extends Event {
193     }
194 
195 }
196