/* * 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; } }