110673SKrishnendu.Sadhukhan@Sun.COM /* 210673SKrishnendu.Sadhukhan@Sun.COM * CDDL HEADER START 310673SKrishnendu.Sadhukhan@Sun.COM * 410673SKrishnendu.Sadhukhan@Sun.COM * The contents of this file are subject to the terms of the 510673SKrishnendu.Sadhukhan@Sun.COM * Common Development and Distribution License (the "License"). 610673SKrishnendu.Sadhukhan@Sun.COM * You may not use this file except in compliance with the License. 710673SKrishnendu.Sadhukhan@Sun.COM * 810673SKrishnendu.Sadhukhan@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 910673SKrishnendu.Sadhukhan@Sun.COM * or http://www.opensolaris.org/os/licensing. 1010673SKrishnendu.Sadhukhan@Sun.COM * See the License for the specific language governing permissions 1110673SKrishnendu.Sadhukhan@Sun.COM * and limitations under the License. 1210673SKrishnendu.Sadhukhan@Sun.COM * 1310673SKrishnendu.Sadhukhan@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1410673SKrishnendu.Sadhukhan@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1510673SKrishnendu.Sadhukhan@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1610673SKrishnendu.Sadhukhan@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1710673SKrishnendu.Sadhukhan@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1810673SKrishnendu.Sadhukhan@Sun.COM * 1910673SKrishnendu.Sadhukhan@Sun.COM * CDDL HEADER END 2010673SKrishnendu.Sadhukhan@Sun.COM */ 2110673SKrishnendu.Sadhukhan@Sun.COM /* 2210673SKrishnendu.Sadhukhan@Sun.COM * Copyright (c) 2008-2009, Intel Corporation. 2310673SKrishnendu.Sadhukhan@Sun.COM * All Rights Reserved. 2410673SKrishnendu.Sadhukhan@Sun.COM */ 2510673SKrishnendu.Sadhukhan@Sun.COM 2610673SKrishnendu.Sadhukhan@Sun.COM #define MAX_TAG 8 2710673SKrishnendu.Sadhukhan@Sun.COM #define MAX_STACK 64 2810673SKrishnendu.Sadhukhan@Sun.COM 2910673SKrishnendu.Sadhukhan@Sun.COM #pragma D option aggsize=8m 3010673SKrishnendu.Sadhukhan@Sun.COM #pragma D option bufsize=16m 3110673SKrishnendu.Sadhukhan@Sun.COM #pragma D option dynvarsize=16m 3210673SKrishnendu.Sadhukhan@Sun.COM #pragma D option aggrate=0 3310673SKrishnendu.Sadhukhan@Sun.COM #pragma D option stackframes=MAX_STACK 3410673SKrishnendu.Sadhukhan@Sun.COM /* 3510673SKrishnendu.Sadhukhan@Sun.COM * Our D script needs to compile even if some of the TRANSLATE probes cannot 3610673SKrishnendu.Sadhukhan@Sun.COM * be found. Missing probes can be caused by older kernel, different 3710673SKrishnendu.Sadhukhan@Sun.COM * architecture, unloaded modules etc. 3810673SKrishnendu.Sadhukhan@Sun.COM */ 3910673SKrishnendu.Sadhukhan@Sun.COM #pragma D option zdefs 4010673SKrishnendu.Sadhukhan@Sun.COM 4110673SKrishnendu.Sadhukhan@Sun.COM #if defined(ENABLE_SCHED) 42*11789SKrishnendu.Sadhukhan@Sun.COM #if defined(TRACE_PID) 43*11789SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER / pid == 0 || pid == TRACE_PID / 44*11789SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER_COND(a) / (pid == 0 || pid == TRACE_PID) && (a) / 45*11789SKrishnendu.Sadhukhan@Sun.COM #elif defined(TRACE_PGID) 46*11789SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER / pid == 0 || curpsinfo->pr_pgid == TRACE_PGID / 47*11789SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER_COND(a) 48*11789SKrishnendu.Sadhukhan@Sun.COM / (pid == 0 || curpsinfo->pr_pgid == TRACE_PGID) && (a) / 49*11789SKrishnendu.Sadhukhan@Sun.COM #else 5010673SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER 5110673SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER_COND(a) / (a) / 52*11789SKrishnendu.Sadhukhan@Sun.COM #endif 53*11789SKrishnendu.Sadhukhan@Sun.COM #else /* ENABLE_SCHED */ 54*11789SKrishnendu.Sadhukhan@Sun.COM #if defined(TRACE_PID) 55*11789SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER / pid == TRACE_PID / 56*11789SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER_COND(a) / (pid == TRACE_PID) && (a) / 57*11789SKrishnendu.Sadhukhan@Sun.COM #elif defined(TRACE_PGID) 58*11789SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER / curpsinfo->pr_pgid == TRACE_PGID / 59*11789SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER_COND(a) / (curpsinfo->pr_pgid == TRACE_PGID) && (a) / 6010673SKrishnendu.Sadhukhan@Sun.COM #else 6110673SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER / pid != 0 / 62*11789SKrishnendu.Sadhukhan@Sun.COM #define TRACE_FILTER_COND(a) / (pid != 0) && (a) / 6310673SKrishnendu.Sadhukhan@Sun.COM #endif 64*11789SKrishnendu.Sadhukhan@Sun.COM #endif /* ENABLE_SCHED */ 6510673SKrishnendu.Sadhukhan@Sun.COM 6610673SKrishnendu.Sadhukhan@Sun.COM /* Threshold to filter WAKEABLE latencies. */ 6710673SKrishnendu.Sadhukhan@Sun.COM #define FILTER_THRESHOLD 5000000 6810673SKrishnendu.Sadhukhan@Sun.COM /* From thread.h */ 6910673SKrishnendu.Sadhukhan@Sun.COM #define T_WAKEABLE 2 7010673SKrishnendu.Sadhukhan@Sun.COM 7110673SKrishnendu.Sadhukhan@Sun.COM /* 7210673SKrishnendu.Sadhukhan@Sun.COM * This array is used to store timestamp of when threads are enqueued 7310673SKrishnendu.Sadhukhan@Sun.COM * to dispatch queue. 7410673SKrishnendu.Sadhukhan@Sun.COM * self-> is not accessible when enqueue happens. 7510673SKrishnendu.Sadhukhan@Sun.COM */ 7610673SKrishnendu.Sadhukhan@Sun.COM unsigned long long lt_timestamps[int, int]; 7710673SKrishnendu.Sadhukhan@Sun.COM 7810673SKrishnendu.Sadhukhan@Sun.COM self unsigned int lt_is_block_wakeable; 7910673SKrishnendu.Sadhukhan@Sun.COM self unsigned long long lt_sleep_start; 8010673SKrishnendu.Sadhukhan@Sun.COM self unsigned long long lt_sleep_duration; 8110673SKrishnendu.Sadhukhan@Sun.COM self unsigned long long lt_sch_delay; 8210673SKrishnendu.Sadhukhan@Sun.COM self unsigned int lt_counter; /* only used in low overhead */ 8310673SKrishnendu.Sadhukhan@Sun.COM self unsigned long long lt_timestamp; /* only used in low overhead */ 8410673SKrishnendu.Sadhukhan@Sun.COM self unsigned int lt_stackp; 8510673SKrishnendu.Sadhukhan@Sun.COM self unsigned int lt_prio[int]; 8610673SKrishnendu.Sadhukhan@Sun.COM self string lt_cause[int]; 8710673SKrishnendu.Sadhukhan@Sun.COM 8810673SKrishnendu.Sadhukhan@Sun.COM this unsigned int priority; 8910673SKrishnendu.Sadhukhan@Sun.COM this string cause; 9010673SKrishnendu.Sadhukhan@Sun.COM 9110673SKrishnendu.Sadhukhan@Sun.COM /* 9210673SKrishnendu.Sadhukhan@Sun.COM * Clean up everything, otherwise we will run out of memory. 9310673SKrishnendu.Sadhukhan@Sun.COM */ 9410673SKrishnendu.Sadhukhan@Sun.COM proc:::lwp-exit 9510673SKrishnendu.Sadhukhan@Sun.COM { 9610673SKrishnendu.Sadhukhan@Sun.COM lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] = 0; 9710673SKrishnendu.Sadhukhan@Sun.COM 9810673SKrishnendu.Sadhukhan@Sun.COM self->lt_sleep_start = 0; 9910673SKrishnendu.Sadhukhan@Sun.COM self->lt_is_block_wakeable = 0; 10010673SKrishnendu.Sadhukhan@Sun.COM self->lt_counter = 0; 10110673SKrishnendu.Sadhukhan@Sun.COM self->lt_timestamp = 0; 10210673SKrishnendu.Sadhukhan@Sun.COM 10310673SKrishnendu.Sadhukhan@Sun.COM /* 10410673SKrishnendu.Sadhukhan@Sun.COM * Workaround: no way to clear associative array. 10510673SKrishnendu.Sadhukhan@Sun.COM * We have to manually clear 0 ~ (MAX_TAG-1). 10610673SKrishnendu.Sadhukhan@Sun.COM */ 10710673SKrishnendu.Sadhukhan@Sun.COM 10810673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[0] = 0; 10910673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[1] = 0; 11010673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[2] = 0; 11110673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[3] = 0; 11210673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[4] = 0; 11310673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[5] = 0; 11410673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[6] = 0; 11510673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[7] = 0; 11610673SKrishnendu.Sadhukhan@Sun.COM 11710673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[0] = 0; 11810673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[1] = 0; 11910673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[2] = 0; 12010673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[3] = 0; 12110673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[4] = 0; 12210673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[5] = 0; 12310673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[6] = 0; 12410673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[7] = 0; 12510673SKrishnendu.Sadhukhan@Sun.COM } 12610673SKrishnendu.Sadhukhan@Sun.COM 12710673SKrishnendu.Sadhukhan@Sun.COM #if !defined(ENABLE_LOW_OVERHEAD) 12810673SKrishnendu.Sadhukhan@Sun.COM /* 12910673SKrishnendu.Sadhukhan@Sun.COM * Log timestamp when a thread is taken off the CPU. 13010673SKrishnendu.Sadhukhan@Sun.COM */ 13110673SKrishnendu.Sadhukhan@Sun.COM sched::resume:off-cpu 13210673SKrishnendu.Sadhukhan@Sun.COM TRACE_FILTER_COND(curlwpsinfo->pr_state == SSLEEP) 13310673SKrishnendu.Sadhukhan@Sun.COM { 13410673SKrishnendu.Sadhukhan@Sun.COM self->lt_sleep_start = timestamp; 13510673SKrishnendu.Sadhukhan@Sun.COM self->lt_is_block_wakeable = curthread->t_flag & T_WAKEABLE; 13610673SKrishnendu.Sadhukhan@Sun.COM 13710673SKrishnendu.Sadhukhan@Sun.COM lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] = 13810673SKrishnendu.Sadhukhan@Sun.COM self->lt_sleep_start; 13910673SKrishnendu.Sadhukhan@Sun.COM } 14010673SKrishnendu.Sadhukhan@Sun.COM 14110673SKrishnendu.Sadhukhan@Sun.COM /* 14210673SKrishnendu.Sadhukhan@Sun.COM * Log timestamp when a thread is put on a dispatch queue and becomes runnable. 14310673SKrishnendu.Sadhukhan@Sun.COM */ 14410673SKrishnendu.Sadhukhan@Sun.COM sched:::enqueue 14510673SKrishnendu.Sadhukhan@Sun.COM /lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] != 0/ 14610673SKrishnendu.Sadhukhan@Sun.COM { 14710673SKrishnendu.Sadhukhan@Sun.COM lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] = timestamp; 14810673SKrishnendu.Sadhukhan@Sun.COM } 14910673SKrishnendu.Sadhukhan@Sun.COM 15010673SKrishnendu.Sadhukhan@Sun.COM /* 15110673SKrishnendu.Sadhukhan@Sun.COM * Calculate latency when the thread is actually on the CPU. 15210673SKrishnendu.Sadhukhan@Sun.COM * This is necessary in order to get the right stack. 15310673SKrishnendu.Sadhukhan@Sun.COM */ 15410673SKrishnendu.Sadhukhan@Sun.COM this unsigned long long end; 15510673SKrishnendu.Sadhukhan@Sun.COM this unsigned long long now; 15610673SKrishnendu.Sadhukhan@Sun.COM sched::resume:on-cpu 15710673SKrishnendu.Sadhukhan@Sun.COM /self->lt_sleep_start != 0/ 15810673SKrishnendu.Sadhukhan@Sun.COM { 15910673SKrishnendu.Sadhukhan@Sun.COM this->end = lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid]; 16010673SKrishnendu.Sadhukhan@Sun.COM this->now = timestamp; 16110673SKrishnendu.Sadhukhan@Sun.COM lt_timestamps[curpsinfo->pr_pid, curlwpsinfo->pr_lwpid] = 0; 16210673SKrishnendu.Sadhukhan@Sun.COM this->end = (this->end != 0 && this->end != self->lt_sleep_start) 16310673SKrishnendu.Sadhukhan@Sun.COM ? this->end : this->now; 16410673SKrishnendu.Sadhukhan@Sun.COM 16510673SKrishnendu.Sadhukhan@Sun.COM self->lt_sch_delay = this->now - this->end; 16610673SKrishnendu.Sadhukhan@Sun.COM self->lt_sleep_duration = this->end - self->lt_sleep_start; 16710673SKrishnendu.Sadhukhan@Sun.COM self->lt_sleep_start = 0; 16810673SKrishnendu.Sadhukhan@Sun.COM } 16910673SKrishnendu.Sadhukhan@Sun.COM 17010673SKrishnendu.Sadhukhan@Sun.COM /* 17110673SKrishnendu.Sadhukhan@Sun.COM * Filter: drop all "large" latency when it is interruptible, i.e., sleep() 17210673SKrishnendu.Sadhukhan@Sun.COM * etc. 17310673SKrishnendu.Sadhukhan@Sun.COM */ 17410673SKrishnendu.Sadhukhan@Sun.COM #if defined(ENABLE_FILTER) 17510673SKrishnendu.Sadhukhan@Sun.COM sched::resume:on-cpu 17610673SKrishnendu.Sadhukhan@Sun.COM /self->lt_sleep_duration > FILTER_THRESHOLD && 17710673SKrishnendu.Sadhukhan@Sun.COM self->lt_is_block_wakeable != 0/ 17810673SKrishnendu.Sadhukhan@Sun.COM { 17910673SKrishnendu.Sadhukhan@Sun.COM self->lt_sch_delay = 0; 18010673SKrishnendu.Sadhukhan@Sun.COM self->lt_sleep_duration = 0; 18110673SKrishnendu.Sadhukhan@Sun.COM self->lt_is_block_wakeable = 0; 18210673SKrishnendu.Sadhukhan@Sun.COM } 18310673SKrishnendu.Sadhukhan@Sun.COM #endif /* defined(ENABLE_FILTER) */ 18410673SKrishnendu.Sadhukhan@Sun.COM 18510673SKrishnendu.Sadhukhan@Sun.COM /* 18610673SKrishnendu.Sadhukhan@Sun.COM * Write sleep time to the aggregation. 18710673SKrishnendu.Sadhukhan@Sun.COM * lt_sleep_duration is the duration between the time when a thread is taken 18810673SKrishnendu.Sadhukhan@Sun.COM * off the CPU and the time when it is enqueued again. 18910673SKrishnendu.Sadhukhan@Sun.COM */ 19010673SKrishnendu.Sadhukhan@Sun.COM sched::resume:on-cpu 19110673SKrishnendu.Sadhukhan@Sun.COM /self->lt_sleep_duration != 0/ 19210673SKrishnendu.Sadhukhan@Sun.COM { 19310673SKrishnendu.Sadhukhan@Sun.COM this->cause = self->lt_stackp > 0 ? 19410673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[self->lt_stackp - 1] : ""; 19510673SKrishnendu.Sadhukhan@Sun.COM this->priority = self->lt_stackp > 0 ? 19610673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[self->lt_stackp - 1] : 0; 19710673SKrishnendu.Sadhukhan@Sun.COM 19810673SKrishnendu.Sadhukhan@Sun.COM @lt_call_count[pid, tid, stack(), this->cause, 19910673SKrishnendu.Sadhukhan@Sun.COM this->priority] = count(); 20010673SKrishnendu.Sadhukhan@Sun.COM @lt_call_sum[pid, tid, stack(), this->cause, 20110673SKrishnendu.Sadhukhan@Sun.COM this->priority] = sum(self->lt_sleep_duration); 20210673SKrishnendu.Sadhukhan@Sun.COM @lt_call_max[pid, tid, stack(), this->cause, 20310673SKrishnendu.Sadhukhan@Sun.COM this->priority] = max(self->lt_sleep_duration); 20410673SKrishnendu.Sadhukhan@Sun.COM 20510673SKrishnendu.Sadhukhan@Sun.COM self->lt_is_block_wakeable = 0; /* Clear the flag to avoid leak */ 20610673SKrishnendu.Sadhukhan@Sun.COM self->lt_sleep_duration = 0; 20710673SKrishnendu.Sadhukhan@Sun.COM } 20810673SKrishnendu.Sadhukhan@Sun.COM 20910673SKrishnendu.Sadhukhan@Sun.COM /* 21010673SKrishnendu.Sadhukhan@Sun.COM * Write time spent in queue to the aggregation. 21110673SKrishnendu.Sadhukhan@Sun.COM * lt_sch_delay is the interval between the time when a thread becomes 21210673SKrishnendu.Sadhukhan@Sun.COM * runnable and the time when it is actually on the CPU. 21310673SKrishnendu.Sadhukhan@Sun.COM */ 21410673SKrishnendu.Sadhukhan@Sun.COM sched::resume:on-cpu 21510673SKrishnendu.Sadhukhan@Sun.COM /self->lt_sch_delay != 0/ 21610673SKrishnendu.Sadhukhan@Sun.COM { 21710673SKrishnendu.Sadhukhan@Sun.COM @lt_named_count[pid, tid, "Wait for available CPU"] = count(); 21810673SKrishnendu.Sadhukhan@Sun.COM @lt_named_sum[pid, tid, "Wait for available CPU"] = 21910673SKrishnendu.Sadhukhan@Sun.COM sum(self->lt_sch_delay); 22010673SKrishnendu.Sadhukhan@Sun.COM @lt_named_max[pid, tid, "Wait for available CPU"] = 22110673SKrishnendu.Sadhukhan@Sun.COM max(self->lt_sch_delay); 22210673SKrishnendu.Sadhukhan@Sun.COM 22310673SKrishnendu.Sadhukhan@Sun.COM self->lt_sch_delay = 0; 22410673SKrishnendu.Sadhukhan@Sun.COM } 22510673SKrishnendu.Sadhukhan@Sun.COM 22610673SKrishnendu.Sadhukhan@Sun.COM /* 22710673SKrishnendu.Sadhukhan@Sun.COM * Probes to track latency caused by spinning on a lock. 22810673SKrishnendu.Sadhukhan@Sun.COM */ 22910673SKrishnendu.Sadhukhan@Sun.COM lockstat:::adaptive-spin 23010673SKrishnendu.Sadhukhan@Sun.COM TRACE_FILTER 23110673SKrishnendu.Sadhukhan@Sun.COM { 23210673SKrishnendu.Sadhukhan@Sun.COM @lt_named_count[pid, tid, "Adapt. lock spin"] = count(); 23310673SKrishnendu.Sadhukhan@Sun.COM @lt_named_sum[pid, tid, "Adapt. lock spin"] = sum(arg1); 23410673SKrishnendu.Sadhukhan@Sun.COM @lt_named_max[pid, tid, "Adapt. lock spin"] = max(arg1); 23510673SKrishnendu.Sadhukhan@Sun.COM } 23610673SKrishnendu.Sadhukhan@Sun.COM 23710673SKrishnendu.Sadhukhan@Sun.COM lockstat:::spin-spin 23810673SKrishnendu.Sadhukhan@Sun.COM TRACE_FILTER 23910673SKrishnendu.Sadhukhan@Sun.COM { 24010673SKrishnendu.Sadhukhan@Sun.COM @lt_named_count[pid, tid, "Spinlock spin"] = count(); 24110673SKrishnendu.Sadhukhan@Sun.COM @lt_named_sum[pid, tid, "Spinlock spin"] = sum(arg1); 24210673SKrishnendu.Sadhukhan@Sun.COM @lt_named_max[pid, tid, "Spinlock spin"] = max(arg1); 24310673SKrishnendu.Sadhukhan@Sun.COM } 24410673SKrishnendu.Sadhukhan@Sun.COM 24510673SKrishnendu.Sadhukhan@Sun.COM /* 24610673SKrishnendu.Sadhukhan@Sun.COM * Probes to track latency caused by blocking on a lock. 24710673SKrishnendu.Sadhukhan@Sun.COM */ 24810673SKrishnendu.Sadhukhan@Sun.COM lockstat:::adaptive-block 24910673SKrishnendu.Sadhukhan@Sun.COM TRACE_FILTER 25010673SKrishnendu.Sadhukhan@Sun.COM { 25110673SKrishnendu.Sadhukhan@Sun.COM @lt_named_count[pid, tid, "#Adapt. lock block"] = count(); 25210673SKrishnendu.Sadhukhan@Sun.COM @lt_named_sum[pid, tid, "#Adapt. lock block"] = sum(arg1); 25310673SKrishnendu.Sadhukhan@Sun.COM @lt_named_max[pid, tid, "#Adapt. lock block"] = max(arg1); 25410673SKrishnendu.Sadhukhan@Sun.COM } 25510673SKrishnendu.Sadhukhan@Sun.COM 25610673SKrishnendu.Sadhukhan@Sun.COM lockstat:::rw-block 25710673SKrishnendu.Sadhukhan@Sun.COM TRACE_FILTER 25810673SKrishnendu.Sadhukhan@Sun.COM { 25910673SKrishnendu.Sadhukhan@Sun.COM @lt_named_count[pid, tid, "#RW. lock block"] = count(); 26010673SKrishnendu.Sadhukhan@Sun.COM @lt_named_sum[pid, tid, "#RW. lock block"] = sum(arg1); 26110673SKrishnendu.Sadhukhan@Sun.COM @lt_named_max[pid, tid, "#RW. lock block"] = max(arg1); 26210673SKrishnendu.Sadhukhan@Sun.COM } 26310673SKrishnendu.Sadhukhan@Sun.COM 26410673SKrishnendu.Sadhukhan@Sun.COM #if defined(ENABLE_SYNCOBJ) 26510673SKrishnendu.Sadhukhan@Sun.COM /* 26610673SKrishnendu.Sadhukhan@Sun.COM * Probes to track latency caused by synchronization objects. 26710673SKrishnendu.Sadhukhan@Sun.COM */ 26810673SKrishnendu.Sadhukhan@Sun.COM this int stype; 26910673SKrishnendu.Sadhukhan@Sun.COM this unsigned long long wchan; 27010673SKrishnendu.Sadhukhan@Sun.COM this unsigned long long wtime; 27110673SKrishnendu.Sadhukhan@Sun.COM 27210673SKrishnendu.Sadhukhan@Sun.COM sched:::wakeup 27310673SKrishnendu.Sadhukhan@Sun.COM /* 27410673SKrishnendu.Sadhukhan@Sun.COM * Currently we are unable to track wakeup from sched, because all its LWP IDs 27510673SKrishnendu.Sadhukhan@Sun.COM * are zero when we trace it and that makes lt_timestamps unusable. 27610673SKrishnendu.Sadhukhan@Sun.COM */ 27710673SKrishnendu.Sadhukhan@Sun.COM /args[1]->pr_pid != 0 && 27810673SKrishnendu.Sadhukhan@Sun.COM lt_timestamps[args[1]->pr_pid, args[0]->pr_lwpid] != 0/ 27910673SKrishnendu.Sadhukhan@Sun.COM { 28010673SKrishnendu.Sadhukhan@Sun.COM this->stype = args[0]->pr_stype; 28110673SKrishnendu.Sadhukhan@Sun.COM this->wchan = args[0]->pr_wchan; 28210673SKrishnendu.Sadhukhan@Sun.COM /* 28310673SKrishnendu.Sadhukhan@Sun.COM * We can use lt_timestamps[] here, because 28410673SKrishnendu.Sadhukhan@Sun.COM * wakeup is always fired before enqueue. 28510673SKrishnendu.Sadhukhan@Sun.COM * After enqueue, lt_timestamps[] will be overwritten. 28610673SKrishnendu.Sadhukhan@Sun.COM */ 28710673SKrishnendu.Sadhukhan@Sun.COM this->wtime = timestamp - lt_timestamps[args[1]->pr_pid, 28810673SKrishnendu.Sadhukhan@Sun.COM args[0]->pr_lwpid]; 28910673SKrishnendu.Sadhukhan@Sun.COM 29010673SKrishnendu.Sadhukhan@Sun.COM @lt_sync_count[args[1]->pr_pid, args[0]->pr_lwpid, this->stype, 29110673SKrishnendu.Sadhukhan@Sun.COM this->wchan] = count(); 29210673SKrishnendu.Sadhukhan@Sun.COM @lt_sync_sum[args[1]->pr_pid, args[0]->pr_lwpid, this->stype, 29310673SKrishnendu.Sadhukhan@Sun.COM this->wchan] = sum(this->wtime); 29410673SKrishnendu.Sadhukhan@Sun.COM @lt_sync_max[args[1]->pr_pid, args[0]->pr_lwpid, this->stype, 29510673SKrishnendu.Sadhukhan@Sun.COM this->wchan] = max(this->wtime); 29610673SKrishnendu.Sadhukhan@Sun.COM } 29710673SKrishnendu.Sadhukhan@Sun.COM #endif /* defined(ENABLE_SYNCOBJ) */ 29810673SKrishnendu.Sadhukhan@Sun.COM 29910673SKrishnendu.Sadhukhan@Sun.COM #else /* !defined(ENABLE_LOW_OVERHEAD) */ 30010673SKrishnendu.Sadhukhan@Sun.COM 30110673SKrishnendu.Sadhukhan@Sun.COM /* 30210673SKrishnendu.Sadhukhan@Sun.COM * This is the low overhead mode. 30310673SKrishnendu.Sadhukhan@Sun.COM * In order to reduce the number of instructions executed during each 30410673SKrishnendu.Sadhukhan@Sun.COM * off-cpu and on-cpu event, we do the following: 30510673SKrishnendu.Sadhukhan@Sun.COM * 30610673SKrishnendu.Sadhukhan@Sun.COM * 1. Use sampling and update aggregations only roughly 1/100 times 30710673SKrishnendu.Sadhukhan@Sun.COM * (SAMPLE_TIMES). 30810673SKrishnendu.Sadhukhan@Sun.COM * 2. Do not track anything other than what is needed for "main" window. 30910673SKrishnendu.Sadhukhan@Sun.COM * 3. Use as few thread local variables as possible. 31010673SKrishnendu.Sadhukhan@Sun.COM */ 31110673SKrishnendu.Sadhukhan@Sun.COM 31210673SKrishnendu.Sadhukhan@Sun.COM #define SAMPLE_TIMES 100 31310673SKrishnendu.Sadhukhan@Sun.COM #define SAMPLE_THRESHOLD 50000000 31410673SKrishnendu.Sadhukhan@Sun.COM 31510673SKrishnendu.Sadhukhan@Sun.COM /* 31610673SKrishnendu.Sadhukhan@Sun.COM * Log timestamp when a thread is off CPU. 31710673SKrishnendu.Sadhukhan@Sun.COM */ 31810673SKrishnendu.Sadhukhan@Sun.COM sched::resume:off-cpu 31910673SKrishnendu.Sadhukhan@Sun.COM TRACE_FILTER_COND(curlwpsinfo->pr_state == SSLEEP) 32010673SKrishnendu.Sadhukhan@Sun.COM { 32110673SKrishnendu.Sadhukhan@Sun.COM self->lt_timestamp = timestamp; 32210673SKrishnendu.Sadhukhan@Sun.COM #if defined(ENABLE_FILTER) 32310673SKrishnendu.Sadhukhan@Sun.COM self->lt_is_block_wakeable = curthread->t_flag & T_WAKEABLE; 32410673SKrishnendu.Sadhukhan@Sun.COM #endif /* defined(ENABLE_FILTER) */ 32510673SKrishnendu.Sadhukhan@Sun.COM } 32610673SKrishnendu.Sadhukhan@Sun.COM 32710673SKrishnendu.Sadhukhan@Sun.COM /* 32810673SKrishnendu.Sadhukhan@Sun.COM * Calculate latency when a thread is actually on the CPU. 32910673SKrishnendu.Sadhukhan@Sun.COM */ 33010673SKrishnendu.Sadhukhan@Sun.COM this int need_skip; 33110673SKrishnendu.Sadhukhan@Sun.COM sched::resume:on-cpu 33210673SKrishnendu.Sadhukhan@Sun.COM /self->lt_timestamp != 0/ 33310673SKrishnendu.Sadhukhan@Sun.COM { 33410673SKrishnendu.Sadhukhan@Sun.COM self->lt_timestamp = timestamp - self->lt_timestamp; 33510673SKrishnendu.Sadhukhan@Sun.COM 33610673SKrishnendu.Sadhukhan@Sun.COM #if defined(ENABLE_FILTER) 33710673SKrishnendu.Sadhukhan@Sun.COM self->lt_timestamp = 33810673SKrishnendu.Sadhukhan@Sun.COM (self->lt_timestamp > FILTER_THRESHOLD && 33910673SKrishnendu.Sadhukhan@Sun.COM self->lt_is_block_wakeable != 0) ? 0 : self->lt_timestamp; 34010673SKrishnendu.Sadhukhan@Sun.COM self->lt_is_block_wakeable = 0; 34110673SKrishnendu.Sadhukhan@Sun.COM #endif /* defined(ENABLE_FILTER) */ 34210673SKrishnendu.Sadhukhan@Sun.COM 34310673SKrishnendu.Sadhukhan@Sun.COM this->need_skip = (self->lt_counter < (SAMPLE_TIMES - 1) && 34410673SKrishnendu.Sadhukhan@Sun.COM self->lt_timestamp <= SAMPLE_THRESHOLD) ? 1 : 0; 34510673SKrishnendu.Sadhukhan@Sun.COM self->lt_timestamp = this->need_skip ? 0 : self->lt_timestamp; 34610673SKrishnendu.Sadhukhan@Sun.COM self->lt_counter += this->need_skip; 34710673SKrishnendu.Sadhukhan@Sun.COM } 34810673SKrishnendu.Sadhukhan@Sun.COM 34910673SKrishnendu.Sadhukhan@Sun.COM /* 35010673SKrishnendu.Sadhukhan@Sun.COM * Track large latency first. 35110673SKrishnendu.Sadhukhan@Sun.COM */ 35210673SKrishnendu.Sadhukhan@Sun.COM sched::resume:on-cpu 35310673SKrishnendu.Sadhukhan@Sun.COM /self->lt_timestamp > SAMPLE_THRESHOLD/ 35410673SKrishnendu.Sadhukhan@Sun.COM { 35510673SKrishnendu.Sadhukhan@Sun.COM this->cause = self->lt_stackp > 0 ? 35610673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[self->lt_stackp - 1] : ""; 35710673SKrishnendu.Sadhukhan@Sun.COM this->priority = self->lt_stackp > 0 ? 35810673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[self->lt_stackp - 1] : 0; 35910673SKrishnendu.Sadhukhan@Sun.COM 36010673SKrishnendu.Sadhukhan@Sun.COM @lt_call_count[pid, tid, stack(), this->cause, 36110673SKrishnendu.Sadhukhan@Sun.COM this->priority] = sum(1); 36210673SKrishnendu.Sadhukhan@Sun.COM @lt_call_sum[pid, tid, stack(), this->cause, 36310673SKrishnendu.Sadhukhan@Sun.COM this->priority] = sum(self->lt_timestamp); 36410673SKrishnendu.Sadhukhan@Sun.COM @lt_call_max[pid, tid, stack(), this->cause, 36510673SKrishnendu.Sadhukhan@Sun.COM this->priority] = max(self->lt_timestamp); 36610673SKrishnendu.Sadhukhan@Sun.COM 36710673SKrishnendu.Sadhukhan@Sun.COM self->lt_timestamp = 0; 36810673SKrishnendu.Sadhukhan@Sun.COM } 36910673SKrishnendu.Sadhukhan@Sun.COM 37010673SKrishnendu.Sadhukhan@Sun.COM /* 37110673SKrishnendu.Sadhukhan@Sun.COM * If we fall back to this probe, that means the latency is small and counter 37210673SKrishnendu.Sadhukhan@Sun.COM * has reached SAMPLE_TIMES. 37310673SKrishnendu.Sadhukhan@Sun.COM */ 37410673SKrishnendu.Sadhukhan@Sun.COM sched::resume:on-cpu 37510673SKrishnendu.Sadhukhan@Sun.COM /self->lt_timestamp != 0/ 37610673SKrishnendu.Sadhukhan@Sun.COM { 37710673SKrishnendu.Sadhukhan@Sun.COM this->cause = self->lt_stackp > 0 ? 37810673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[self->lt_stackp - 1] : ""; 37910673SKrishnendu.Sadhukhan@Sun.COM this->priority = self->lt_stackp > 0 ? 38010673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[self->lt_stackp - 1] : 0; 38110673SKrishnendu.Sadhukhan@Sun.COM 38210673SKrishnendu.Sadhukhan@Sun.COM /* Need +1 because lt_counter has not been updated in this cycle. */ 38310673SKrishnendu.Sadhukhan@Sun.COM @lt_call_count[pid, tid, stack(), this->cause, 38410673SKrishnendu.Sadhukhan@Sun.COM this->priority] = sum(self->lt_counter + 1); 38510673SKrishnendu.Sadhukhan@Sun.COM @lt_call_sum[pid, tid, stack(), this->cause, 38610673SKrishnendu.Sadhukhan@Sun.COM this->priority] = sum((self->lt_counter + 1) * self->lt_timestamp); 38710673SKrishnendu.Sadhukhan@Sun.COM @lt_call_max[pid, tid, stack(), this->cause, 38810673SKrishnendu.Sadhukhan@Sun.COM this->priority] = max(self->lt_timestamp); 38910673SKrishnendu.Sadhukhan@Sun.COM 39010673SKrishnendu.Sadhukhan@Sun.COM self->lt_timestamp = 0; 39110673SKrishnendu.Sadhukhan@Sun.COM self->lt_counter = 0; 39210673SKrishnendu.Sadhukhan@Sun.COM } 39310673SKrishnendu.Sadhukhan@Sun.COM 39410673SKrishnendu.Sadhukhan@Sun.COM #endif /* !defined(ENABLE_LOW_OVERHEAD) */ 39510673SKrishnendu.Sadhukhan@Sun.COM 39610673SKrishnendu.Sadhukhan@Sun.COM #define TRANSLATE(entryprobe, returnprobe, cause, priority) \ 39710673SKrishnendu.Sadhukhan@Sun.COM entryprobe \ 39810673SKrishnendu.Sadhukhan@Sun.COM TRACE_FILTER_COND(self->lt_stackp == 0 || \ 39910673SKrishnendu.Sadhukhan@Sun.COM (self->lt_stackp < MAX_TAG && \ 40010673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[self->lt_stackp - 1] <= priority) ) \ 40110673SKrishnendu.Sadhukhan@Sun.COM { \ 40210673SKrishnendu.Sadhukhan@Sun.COM self->lt_prio[self->lt_stackp] = priority; \ 40310673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[self->lt_stackp] = cause; \ 40410673SKrishnendu.Sadhukhan@Sun.COM ++self->lt_stackp; \ 40510673SKrishnendu.Sadhukhan@Sun.COM } \ 40610673SKrishnendu.Sadhukhan@Sun.COM returnprobe \ 40710673SKrishnendu.Sadhukhan@Sun.COM TRACE_FILTER_COND(self->lt_stackp > 0 && \ 40810673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[self->lt_stackp - 1] == cause) \ 40910673SKrishnendu.Sadhukhan@Sun.COM { \ 41010673SKrishnendu.Sadhukhan@Sun.COM --self->lt_stackp; \ 41110673SKrishnendu.Sadhukhan@Sun.COM self->lt_cause[self->lt_stackp] = NULL; \ 41210673SKrishnendu.Sadhukhan@Sun.COM } 41310673SKrishnendu.Sadhukhan@Sun.COM 41410673SKrishnendu.Sadhukhan@Sun.COM /* 41510673SKrishnendu.Sadhukhan@Sun.COM * Syscalls have a priority of 10. This is to make sure that latency is 41610673SKrishnendu.Sadhukhan@Sun.COM * traced to one of the syscalls only if nothing else matches. 41710673SKrishnendu.Sadhukhan@Sun.COM * We put this special probe here because it uses "probefunc" variable instead 41810673SKrishnendu.Sadhukhan@Sun.COM * of a constant string. 41910673SKrishnendu.Sadhukhan@Sun.COM */ 42010673SKrishnendu.Sadhukhan@Sun.COM 42110673SKrishnendu.Sadhukhan@Sun.COM TRANSLATE(syscall:::entry, syscall:::return, probefunc, 10) 422