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
27import org.opensolaris.os.dtrace.*;
28import java.util.*;
29
30/**
31 * Assert getAggregate() can explicitly specify the anonymous aggregation.
32 */
33public 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
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
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
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
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
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