/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.opensolaris.os.dtrace;
import java.util.*;
import java.io.*;
import java.beans.*;
/**
* 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
* <a href=http://docs.sun.com/app/docs/doc/817-6223/6mlkidlfv?a=view>
* <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
*/
public final class ProbeData implements Serializable, Comparable <ProbeData> {
static final long serialVersionUID = -7021504416192099215L;
/**
* 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()} */
PROBE,
/** Specifies {@link ProbeData#getEnabledProbeID()} */
EPID,
/** Specifies {@link ProbeData#getRecords()} */
RECORDS
}
/**
* 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
ProbeData(int enabledProbeID, int cpuID, ProbeDescription p,
Flow f, List <Record> recordList)
{
}
/**
* 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 null;
}
static int
compareUnsigned(int i1, int i2)
{
int cmp;
if (i1 < 0) {
if (i2 < 0) {
cmp = (i1 < i2 ? -1 : (i1 > i2 ? 1 : 0));
} else {
cmp = 1; // negative > positive
}
} else if (i2 < 0) {
cmp = -1; // positive < negative
} else {
cmp = (i1 < i2 ? -1 : (i1 > i2 ? 1 : 0));
}
return cmp;
}
static int
compareUnsigned(long i1, long i2)
{
int cmp;
if (i1 < 0) {
if (i2 < 0) {
cmp = (i1 < i2 ? -1 : (i1 > i2 ? 1 : 0));
} else {
cmp = 1; // negative > positive
}
} else if (i2 < 0) {
cmp = -1; // positive < negative
} else {
cmp = (i1 < i2 ? -1 : (i1 > i2 ? 1 : 0));
}
return cmp;
}
static int
compareUnsigned(byte i1, byte i2)
{
int cmp;
if (i1 < 0) {
if (i2 < 0) {
cmp = (i1 < i2 ? -1 : (i1 > i2 ? 1 : 0));
} else {
cmp = 1; // negative > positive
}
} else if (i2 < 0) {
cmp = -1; // positive < negative
} else {
cmp = (i1 < i2 ? -1 : (i1 > i2 ? 1 : 0));
}
return cmp;
}
static int
compareByteArrays(byte[] a1, byte[] a2)
{
int cmp = 0;
int len1 = a1.length;
int len2 = a2.length;
for (int i = 0; (cmp == 0) && (i < len1) && (i < len2); ++i) {
cmp = compareUnsigned(a1[i], a2[i]);
}
if (cmp == 0) {
cmp = (len1 < len2 ? -1 : (len1 > len2 ? 1 : 0));
}
return cmp;
}
@SuppressWarnings("unchecked")
static int
compareUnsigned(Comparable v1, Comparable v2)
{
int cmp;
if (v1 instanceof Integer) {
int i1 = Integer.class.cast(v1);
int i2 = Integer.class.cast(v2);
cmp = compareUnsigned(i1, i2);
} else if (v1 instanceof Long) {
long i1 = Long.class.cast(v1);
long i2 = Long.class.cast(v2);
cmp = compareUnsigned(i1, i2);
} else {
cmp = v1.compareTo(v2);
}
return cmp;
}
/**
* 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
getEnabledProbeID()
{
return -1;
}
/**
* 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 0;
}
/**
* Gets the enabled probe description. Identifies the enabled probe
* that fired and generated this {@code ProbeData}.
*
* @return non-null probe description
*/
public ProbeDescription
getEnabledProbeDescription()
{
return null;
}
/**
* 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 null;
}
/**
* 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)
*/
public List <Record>
getRecords()
{
return Collections.EMPTY_LIST;
}
/**
* 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
compareTo(ProbeData d)
{
return 0;
}
}