/*
* 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 (c) 2008-2009, Intel Corporation.
* All Rights Reserved.
*/
#define MAX_TAG 8
#define MAX_STACK 64
/*
* Our D script needs to compile even if some of the TRANSLATE probes cannot
* be found. Missing probes can be caused by older kernel, different
* architecture, unloaded modules etc.
*/
#if defined(ENABLE_SCHED)
#if defined(TRACE_PID)
#elif defined(TRACE_PGID)
#define TRACE_FILTER_COND(a)
#else
#define TRACE_FILTER
#define TRACE_FILTER_COND(a) / (a) /
#endif
#else /* ENABLE_SCHED */
#if defined(TRACE_PID)
#elif defined(TRACE_PGID)
#else
#define TRACE_FILTER / pid != 0 /
#define TRACE_FILTER_COND(a) / (pid != 0) && (a) /
#endif
#endif /* ENABLE_SCHED */
/* Threshold to filter WAKEABLE latencies. */
#define FILTER_THRESHOLD 5000000
/* From thread.h */
#define T_WAKEABLE 2
/*
* This array is used to store timestamp of when threads are enqueued
* to dispatch queue.
* self-> is not accessible when enqueue happens.
*/
unsigned long long lt_timestamps[int, int];
self unsigned int lt_is_block_wakeable;
self unsigned long long lt_sleep_start;
self unsigned long long lt_sleep_duration;
self unsigned long long lt_sch_delay;
/*
* Clean up everything, otherwise we will run out of memory.
*/
{
self->lt_sleep_start = 0;
self->lt_is_block_wakeable = 0;
self->lt_counter = 0;
self->lt_timestamp = 0;
/*
* Workaround: no way to clear associative array.
* We have to manually clear 0 ~ (MAX_TAG-1).
*/
}
#if !defined(ENABLE_LOW_OVERHEAD)
/*
* Log timestamp when a thread is taken off the CPU.
*/
{
}
/*
* Log timestamp when a thread is put on a dispatch queue and becomes runnable.
*/
{
}
/*
* Calculate latency when the thread is actually on the CPU.
* This is necessary in order to get the right stack.
*/
/self->lt_sleep_start != 0/
{
self->lt_sleep_start = 0;
}
/*
* Filter: drop all "large" latency when it is interruptible, i.e., sleep()
* etc.
*/
#if defined(ENABLE_FILTER)
self->lt_is_block_wakeable != 0/
{
self->lt_sch_delay = 0;
self->lt_sleep_duration = 0;
self->lt_is_block_wakeable = 0;
}
#endif /* defined(ENABLE_FILTER) */
/*
* Write sleep time to the aggregation.
* lt_sleep_duration is the duration between the time when a thread is taken
* off the CPU and the time when it is enqueued again.
*/
/self->lt_sleep_duration != 0/
{
self->lt_sleep_duration = 0;
}
/*
* Write time spent in queue to the aggregation.
* lt_sch_delay is the interval between the time when a thread becomes
* runnable and the time when it is actually on the CPU.
*/
/self->lt_sch_delay != 0/
{
self->lt_sch_delay = 0;
}
/*
* Probes to track latency caused by spinning on a lock.
*/
{
}
{
}
/*
* Probes to track latency caused by blocking on a lock.
*/
{
}
{
}
#if defined(ENABLE_SYNCOBJ)
/*
* Probes to track latency caused by synchronization objects.
*/
/*
* Currently we are unable to track wakeup from sched, because all its LWP IDs
* are zero when we trace it and that makes lt_timestamps unusable.
*/
{
/*
* We can use lt_timestamps[] here, because
* wakeup is always fired before enqueue.
* After enqueue, lt_timestamps[] will be overwritten.
*/
}
#endif /* defined(ENABLE_SYNCOBJ) */
#else /* !defined(ENABLE_LOW_OVERHEAD) */
/*
* This is the low overhead mode.
* In order to reduce the number of instructions executed during each
* off-cpu and on-cpu event, we do the following:
*
* 1. Use sampling and update aggregations only roughly 1/100 times
* (SAMPLE_TIMES).
* 2. Do not track anything other than what is needed for "main" window.
* 3. Use as few thread local variables as possible.
*/
#define SAMPLE_TIMES 100
#define SAMPLE_THRESHOLD 50000000
/*
* Log timestamp when a thread is off CPU.
*/
{
#if defined(ENABLE_FILTER)
#endif /* defined(ENABLE_FILTER) */
}
/*
* Calculate latency when a thread is actually on the CPU.
*/
/self->lt_timestamp != 0/
{
#if defined(ENABLE_FILTER)
self->lt_timestamp =
self->lt_is_block_wakeable = 0;
#endif /* defined(ENABLE_FILTER) */
}
/*
* Track large latency first.
*/
{
self->lt_timestamp = 0;
}
/*
* If we fall back to this probe, that means the latency is small and counter
* has reached SAMPLE_TIMES.
*/
/self->lt_timestamp != 0/
{
/* Need +1 because lt_counter has not been updated in this cycle. */
self->lt_timestamp = 0;
self->lt_counter = 0;
}
#endif /* !defined(ENABLE_LOW_OVERHEAD) */
{ \
} \
{ \
}
/*
* Syscalls have a priority of 10. This is to make sure that latency is
* traced to one of the syscalls only if nothing else matches.
* We put this special probe here because it uses "probefunc" variable instead
* of a constant string.
*/