ProbeData.java revision fb3fb4f3d76d55b64440afd0af72775dfad3bd1d
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
* ident "%Z%%M% %I% %E% SMI"
*/
/**
* Data generated when a DTrace probe fires, contains one record for
* every record-generating action in the probe. (Some D actions, such
* as {@code clear()}, do not generate a {@code ProbeData} record.) A
* {@link Consumer} gets data from DTrace by registering a {@link
* ConsumerListener listener} to get probe data whenever a probe fires:
* <pre><code>
* Consumer consumer = new LocalConsumer();
* consumer.addConsumerListener(new ConsumerAdapter() {
* public void dataReceived(DataEvent e) {
* ProbeData probeData = e.getProbeData();
* System.out.println(probeData);
* }
* });
* </code></pre>
* Getting DTrace to generate that probe data involves compiling,
* enabling, and running a D program:
* <pre><code>
* try {
* consumer.open();
* consumer.compile(program);
* consumer.enable(); // instruments code at matching probe points
* consumer.go(); // non-blocking; generates probe data in background
* } catch (DTraceException e) {
* e.printStackTrace();
* }
* </code></pre>
* Currently the {@code ProbeData} instance does not record a timestamp.
* If you need a timestamp, trace the built-in {@code timestamp}
* variable in your D program. (See the
* <b>Built-in Variables</b></a> section of the <b>Variables</b> chapter of
* the <i>Solaris Dynamic Tracing Guide</i>).
* <p>
* Immutable. Supports persistence using {@link java.beans.XMLEncoder}.
*
* @see Consumer#addConsumerListener(ConsumerListener l)
* @see ConsumerListener#dataReceived(DataEvent e)
*
* @author Tom Erickson
*/
static final long serialVersionUID = -7021504416192099215L;
static {
try {
"enabledProbeDescription", "flow", "records"});
} catch (IntrospectionException e) {
}
}
static {
try {
} catch (Throwable e) {
e.printStackTrace();
}
}
/** @serial */
private int epid;
/** @serial */
private int cpu;
/** @serial */
private ProbeDescription enabledProbeDescription;
/** @serial */
// Scratch data, one element per native probedata->dtpda_edesc->dtepd_nrecs
// element, cleared after records list is fully populated.
/** @serial */
/**
* Enumerates the fields by which {@link ProbeData} may be sorted
* using the {@link #getComparator(KeyField[] f) getComparator()}
* convenience method.
*/
public enum KeyField {
/** Specifies {@link ProbeData#getCPU()} */
CPU,
/** Specifies {@link ProbeData#getEnabledProbeDescription()} */
/** Specifies {@link ProbeData#getEnabledProbeID()} */
EPID,
/** Specifies {@link ProbeData#getRecords()} */
}
/**
* Called by native code.
*/
private
Flow f, int nativeElementCount)
{
flow = f;
validate();
}
/**
* Creates a probe data instance with the given properties and list
* of records. Supports XML persistence.
*
* @param enabledProbeID identifies the enabled probe that fired;
* the ID is generated by the native DTrace library to distinguish
* all probes enabled by the source consumer (as opposed to
* all probes on the system)
* @param cpuID non-negative ID, identifies the CPU on which the
* probe fired
* @param p identifies the enabled probe that fired
* @param f current state of control flow (entry or return and depth
* in call stack) at time of probe firing, included if {@link
* Option#flowindent flowindent} option used, {@code null} otherwise
* @param recordList list of records generated by D actions in the
* probe that fired, one record per action, may be empty
* @throws NullPointerException if the given probe description or
* list of records is {@code null}
*/
public
{
flow = f;
validate();
}
private void
validate()
{
if (enabledProbeDescription == null) {
throw new NullPointerException(
"enabled probe description is null");
}
throw new NullPointerException("record list is null");
}
}
private void
{
nativeElements.add(o);
}
/**
* Called by native code.
*/
private void
{
}
/**
* Called by native code.
*/
private void
addTraceRecord(int i)
{
// trace() value is preceded by one null for every D program
// statement preceding trace() that is not a D action, such as
// assignment to a variable (results in a native probedata
// record with no data).
}
/**
* Called by native code.
*/
private void
{
if (stack instanceof KernelStackRecord) {
} else if (stack instanceof UserStackRecord) {
} else {
throw new IllegalStateException("no stack record at index " + i);
}
}
/**
* Called by native code.
*/
private void
{
}
/**
* Called by native code.
*/
private void
{
}
private PrintaRecord
{
if (record instanceof PrintaRecord) {
}
}
return printa;
}
/**
* Called by native code.
*/
private void
{
throw new IllegalStateException(
"No PrintaRecord in this ProbeData");
}
}
/**
* Called by native code.
*/
private void
{
throw new IllegalStateException(
"No PrintaRecord in this ProbeData");
}
printa.invalidate();
}
/**
* Called by native code.
*/
private void
{
throw new IllegalStateException(
"No PrintaRecord in this ProbeData");
}
}
/**
* Called by native code.
*/
private void
addExitRecord(int i)
{
}
/**
* Called by native code. Attaches native probedata elements cached
* between the given first index and last index inclusive to the most
* recently added record if applicable.
*/
private void
{
if (record instanceof PrintfRecord) {
Object e;
e = nativeElements.get(i);
if (e == null) {
// printf() unformatted elements are preceded by one
// null for every D program statement preceding the
// printf() that is not a D action, such as
// assignment to a variable (generates a probedata
// record with no data).
continue;
}
}
}
}
/**
* Called by native code.
*/
void
{
}
/**
* Called by native code.
*/
private void
{
if (record instanceof PrintfRecord) {
}
}
/**
* Convenience method, gets a comparator that sorts multiple {@link
* ProbeDescription} instances by the specified field or fields. If
* more than one sort field is specified, the probe data are sorted
* by the first field, and in case of a tie, by the second field,
* and so on, in the order that the fields are specified.
*
* @param f field specifiers given in descending order of sort
* priority; lower priority fields are only compared (as a tie
* breaker) when all higher priority fields are equal
* @return non-null probe data comparator that sorts by the
* specified sort fields in the given order
*/
public static Comparator <ProbeData>
getComparator(KeyField ... f)
{
return new Cmp(f);
}
private KeyField[] sortFields;
private
{
sortFields = f;
}
public int
{
}
}
/**
* @throws ClassCastException if records or their data are are not
* mutually comparable
*/
@SuppressWarnings("unchecked")
private static int
{
int cmp;
if (r1 instanceof ScalarRecord) {
} else if (r1 instanceof PrintfRecord) {
} else if (r1 instanceof ExitRecord) {
} else {
throw new IllegalArgumentException("Unexpected record type: " +
}
return cmp;
}
/**
* @throws ClassCastException if lists are not mutually comparable
* because corresponding list elements are not comparable or the
* list themselves are different lengths
*/
private static int
{
throw new ClassCastException("Record lists of different " +
"length are not comparable (lengths are " +
}
int cmp;
if (cmp != 0) {
return cmp;
}
}
return 0;
}
private static int
{
int cmp;
for (KeyField f : comparedFields) {
switch (f) {
case CPU:
break;
case PROBE:
break;
case EPID:
break;
case RECORDS:
break;
default:
throw new IllegalArgumentException(
"Unexpected sort field " + f);
}
if (cmp != 0) {
return cmp;
}
}
return 0;
}
/**
* Gets the enabled probe ID. Identifies the enabled probe that
* fired and generated this {@code ProbeData}. The "epid" is
* different from {@link ProbeDescription#getID()} in that it
* identifies a probe among all probes enabled by the source {@link
* Consumer}, rather than among all the probes on the system.
*
* @return the enabled probe ID generated by the native DTrace
* library
*/
public int
{
return epid;
}
/**
* Gets the ID of the CPU on which the probe fired.
*
* @return ID of the CPU on which the probe fired
*/
public int
getCPU()
{
return cpu;
}
/**
* Gets the enabled probe description. Identifies the enabled probe
* that fired and generated this {@code ProbeData}.
*
* @return non-null probe description
*/
public ProbeDescription
{
return enabledProbeDescription;
}
/**
* Gets the current state of control flow (function entry or return,
* and depth in call stack) at the time of the probe firing that
* generated this {@code ProbeData} instance, or {@code null} if
* such information was not requested with the {@code flowindent}
* option.
*
* @return a description of control flow across function boundaries,
* or {@code null} if {@code Consumer.getOption(Option.flowindent)}
* returns {@link Option#UNSET}
* @see Consumer#setOption(String option)
* @see Option#flowindent
*/
public Flow
getFlow()
{
return flow;
}
/**
* Gets the records generated by the actions of the probe that
* fired, in the same order as the actions that generated the
* records. The returned list includes one record for every
* record-generating D action (some D actions, such as {@code
* clear()}, do not generate records).
*
* @return non-null, unmodifiable list view of the records belonging
* to this {@code ProbeData} in the order of the actions in the
* DTrace probe that generated them (record-producing actions are
* generally those that produce output, such as {@code printf()},
* but also the {@code exit()} action)
*/
{
}
/**
* Natural ordering of probe data. Sorts probe data by records
* first, then if record data is equal, by enabled probe ID.
*
* @param d probe data to be compared with this probe data
* @return a negative number, zero, or a positive number as this
* probe data is less than, equal to, or greater than the given
* probe data
* @see ProbeData#getComparator(KeyField[] f)
* @throws NullPointerException if the given probe data is
* {@code null}
* @throws ClassCastException if record lists of both {@code
* ProbeData} instances are not mutually comparable because
* corresponding list elements are not comparable or the lists
* themselves are different lengths
*/
public int
{
return DEFAULT_CMP.compare(this, d);
}
private void
throws IOException, ClassNotFoundException
{
s.defaultReadObject();
// Defensively copy record list _before_ validating.
// Check class invariants
try {
validate();
} catch (Exception e) {
throw new InvalidObjectException(e.getMessage());
}
}
/**
* Gets a string representation of this {@code ProbeData} instance
* useful for logging and not intended for display. The exact
* details of the representation are unspecified and subject to
* change, but the following format may be regarded as typical:
* <pre><code>
* class-name[property1 = value1, property2 = value2]
* </code></pre>
*/
public String
toString()
{
if (i > 0) {
}
if (record instanceof ValueRecord) {
} else {
}
} else {
}
}
}
}