1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 import org.opensolaris.os.dtrace.*;
28 import java.util.*;
29 
30 /**
31  * Assert getAggregate() can explicitly specify the anonymous aggregation.
32  */
33 public class TestGetAggregate {
34     static final String programString =
35 	    "profile:::tick-50ms" +
36 	    "{" +
37 	    "        @ = count();" +
38 	    "        @a = count();" +
39 	    "}";
40 
41     static final String ANONYMOUS_AGGREGATION = "";
42     static final int TICK = 50;
43     static final int EXPECTED_TICKS = 3;
44     static final int INTERVALS = 4;
45 
46     static void
testIncluded(Consumer consumer, String ... aggregationNames)47     testIncluded(Consumer consumer, String ... aggregationNames)
48 	    throws DTraceException, InterruptedException
49     {
50 	Aggregate aggregate;
51 	Set <String> included = new HashSet <String> ();
52 	int n = 1;
53 
54 	for (String name : aggregationNames) {
55 	    included.add(name);
56 	}
57 
58 	// Wait up to a full second to obtain aggregate data. Without a
59 	// time limit, we'll loop forever if no aggregation was
60 	// successfully included.
61 	do {
62 	    Thread.sleep(TICK);
63 	    aggregate = consumer.getAggregate(included, null);
64 	} while (aggregate.asMap().isEmpty() && n++ < (1000 / TICK));
65 
66 	for (String name : included) {
67 	    if (aggregate.getAggregation(name) == null) {
68 		throw new IllegalStateException("@" + name +
69 			" was explicitly included but did not appear " +
70 			"in the aggregate");
71 	    }
72 	}
73 	for (Aggregation a : aggregate.getAggregations()) {
74 	    if (!included.contains(a.getName())) {
75 		throw new IllegalStateException("@" + a.getName() +
76 			" was not explicitly included but appeared " +
77 			"in the aggregate anyway");
78 	    }
79 	}
80 
81 	if (!consumer.isRunning()) {
82 	    throw new IllegalStateException("consumer exited");
83 	}
84     }
85 
86     static void
testCleared(Consumer consumer, String ... aggregationNames)87     testCleared(Consumer consumer, String ... aggregationNames)
88 	    throws DTraceException, InterruptedException
89     {
90 	Aggregate aggregate;
91 	AggregationRecord rec;
92 	long value;
93 	Long firstValue;
94 	int n = 1;
95 	Map <String, Long> firstValues = new HashMap <String, Long> ();
96 	Set <String> cleared = new HashSet <String> ();
97 
98 	for (String name : aggregationNames) {
99 	    cleared.add(name);
100 	}
101 
102 	do {
103 	    Thread.sleep(TICK);
104 	    aggregate = consumer.getAggregate(null, cleared);
105 	} while (aggregate.asMap().isEmpty() && n++ < (1000 / TICK));
106 	n = 1;
107 
108 	do {
109 	    Thread.sleep(TICK * EXPECTED_TICKS);
110 	    aggregate = consumer.getAggregate(null, cleared);
111 
112 	    for (Aggregation a : aggregate.getAggregations()) {
113 		if (!firstValues.containsKey(a.getName())) {
114 		    rec = a.getRecord(Tuple.EMPTY);
115 		    value = rec.getValue().getValue().longValue();
116 		    firstValues.put(a.getName(), value);
117 		}
118 	    }
119 	} while (consumer.isRunning() && n++ < INTERVALS);
120 
121 	for (Aggregation a : aggregate.getAggregations()) {
122 	    rec = a.getRecord(Tuple.EMPTY);
123 	    value = rec.getValue().getValue().longValue();
124 	    firstValue = firstValues.get(a.getName());
125 
126 	    if (cleared.contains(a.getName())) {
127 		// last value should be about the same as first value
128 		if (value > (firstValue * 2)) {
129 		    throw new IllegalStateException(
130 			    "@" + a.getName() + " should have " +
131 			    "been cleared but instead grew from " +
132 			    firstValue + " to " + value);
133 		}
134 	    } else {
135 		// last value should be about (INTERVALS * firstValue)
136 		if (value < (firstValue * 2)) {
137 		    throw new IllegalStateException(
138 			    "@" + a.getName() + " should have " +
139 			    "accumulated a running total but " +
140 			    "instead went from " +
141 			    firstValue + " to " + value);
142 		}
143 	    }
144 	}
145 
146 	if (!consumer.isRunning()) {
147 	    throw new IllegalStateException("consumer exited");
148 	}
149     }
150 
151     static Integer includedStatus;
152     static Integer clearedStatus;
153 
154     static void
startIncludedTest()155     startIncludedTest()
156     {
157 	final Consumer consumer = new LocalConsumer();
158 	consumer.addConsumerListener(new ConsumerAdapter() {
159 	    public void consumerStarted(ConsumerEvent e) {
160 		new Thread(new Runnable() {
161 		    public void run() {
162 			try {
163 			    testIncluded(consumer, ANONYMOUS_AGGREGATION);
164 			    includedStatus = 0;
165 			} catch (Exception e) {
166 			    includedStatus = 1;
167 			    e.printStackTrace();
168 			} finally {
169 			    consumer.abort();
170 			}
171 		    }
172 		}).start();
173 	    }
174 	});
175 
176 	try {
177 	    consumer.open();
178 	    consumer.setOption(Option.aggrate, Option.millis(TICK));
179 	    consumer.compile(programString);
180 	    consumer.enable();
181 	    consumer.go();
182 	} catch (Exception e) {
183 	    includedStatus = 1;
184 	    e.printStackTrace();
185 	}
186     }
187 
188     static void
startClearedTest()189     startClearedTest()
190     {
191 	final Consumer consumer = new LocalConsumer();
192 	consumer.addConsumerListener(new ConsumerAdapter() {
193 	    public void consumerStarted(ConsumerEvent e) {
194 		new Thread(new Runnable() {
195 		    public void run() {
196 			try {
197 			    testCleared(consumer, ANONYMOUS_AGGREGATION);
198 			    clearedStatus = 0;
199 			} catch (Exception e) {
200 			    clearedStatus = 1;
201 			    e.printStackTrace();
202 			} finally {
203 			    consumer.abort();
204 			}
205 		    }
206 		}).start();
207 	    }
208 	});
209 
210 	try {
211 	    consumer.open();
212 	    consumer.setOption(Option.aggrate, Option.millis(TICK));
213 	    consumer.compile(programString);
214 	    consumer.enable();
215 	    consumer.go();
216 	} catch (Exception e) {
217 	    clearedStatus = 1;
218 	    e.printStackTrace();
219 	}
220     }
221 
222     public static void
main(String[] args)223     main(String[] args)
224     {
225 	startIncludedTest();
226 
227 	do {
228 	    try {
229 		Thread.sleep(TICK);
230 	    } catch (InterruptedException e) {
231 		e.printStackTrace();
232 	    }
233 	} while (includedStatus == null);
234 
235 	startClearedTest();
236 
237 	do {
238 	    try {
239 		Thread.sleep(TICK);
240 	    } catch (InterruptedException e) {
241 		e.printStackTrace();
242 	    }
243 	} while (clearedStatus == null);
244 
245 	if (includedStatus != 0 || clearedStatus != 0) {
246 	    System.out.println("Failure");
247 	    System.exit(1);
248 	}
249 
250 	System.out.println("Success");
251     }
252 }
253