xref: /illumos-gate/usr/src/cmd/latencytop/stat.c (revision 486c6fda)
1*486c6fdaSRichard Lowe /*
2*486c6fdaSRichard Lowe  * CDDL HEADER START
3*486c6fdaSRichard Lowe  *
4*486c6fdaSRichard Lowe  * The contents of this file are subject to the terms of the
5*486c6fdaSRichard Lowe  * Common Development and Distribution License (the "License").
6*486c6fdaSRichard Lowe  * You may not use this file except in compliance with the License.
7*486c6fdaSRichard Lowe  *
8*486c6fdaSRichard Lowe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*486c6fdaSRichard Lowe  * or http://www.opensolaris.org/os/licensing.
10*486c6fdaSRichard Lowe  * See the License for the specific language governing permissions
11*486c6fdaSRichard Lowe  * and limitations under the License.
12*486c6fdaSRichard Lowe  *
13*486c6fdaSRichard Lowe  * When distributing Covered Code, include this CDDL HEADER in each
14*486c6fdaSRichard Lowe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*486c6fdaSRichard Lowe  * If applicable, add the following below this CDDL HEADER, with the
16*486c6fdaSRichard Lowe  * fields enclosed by brackets "[]" replaced with your own identifying
17*486c6fdaSRichard Lowe  * information: Portions Copyright [yyyy] [name of copyright owner]
18*486c6fdaSRichard Lowe  *
19*486c6fdaSRichard Lowe  * CDDL HEADER END
20*486c6fdaSRichard Lowe  */
21*486c6fdaSRichard Lowe /*
22*486c6fdaSRichard Lowe  * Copyright (c) 2008-2009, Intel Corporation.
23*486c6fdaSRichard Lowe  * All Rights Reserved.
24*486c6fdaSRichard Lowe  */
25*486c6fdaSRichard Lowe 
26*486c6fdaSRichard Lowe #include <stdlib.h>
27*486c6fdaSRichard Lowe #include <stdio.h>
28*486c6fdaSRichard Lowe #include <memory.h>
29*486c6fdaSRichard Lowe #include <string.h>
30*486c6fdaSRichard Lowe #include <limits.h>
31*486c6fdaSRichard Lowe #include <sys/stat.h>
32*486c6fdaSRichard Lowe 
33*486c6fdaSRichard Lowe #include "latencytop.h"
34*486c6fdaSRichard Lowe 
35*486c6fdaSRichard Lowe /* Statistics for each process/thread. */
36*486c6fdaSRichard Lowe typedef struct _lt_stat_collection lt_stat_collection_t;
37*486c6fdaSRichard Lowe typedef gboolean (*check_child_func_t) (gpointer key,
38*486c6fdaSRichard Lowe     lt_stat_collection_t *stat, void *user);
39*486c6fdaSRichard Lowe 
40*486c6fdaSRichard Lowe typedef struct {
41*486c6fdaSRichard Lowe 	lt_stat_entry_t lt_grp_summary;
42*486c6fdaSRichard Lowe 	/* cause_id -> stat entry */
43*486c6fdaSRichard Lowe 	GHashTable *lt_grp_cidlist;
44*486c6fdaSRichard Lowe } lt_datagroup_t;
45*486c6fdaSRichard Lowe 
46*486c6fdaSRichard Lowe #define	NGROUPS			2
47*486c6fdaSRichard Lowe #define	GROUP_CAUSE		0
48*486c6fdaSRichard Lowe #define	GROUP_SOBJ		1
49*486c6fdaSRichard Lowe 
50*486c6fdaSRichard Lowe /*
51*486c6fdaSRichard Lowe  * A data collection hierarchy involving three entities - system, process
52*486c6fdaSRichard Lowe  * and thread. The hierarchic relationship is as follows :
53*486c6fdaSRichard Lowe  *
54*486c6fdaSRichard Lowe  *		1 system -> 1 or more processes -> 1 or more threads
55*486c6fdaSRichard Lowe  */
56*486c6fdaSRichard Lowe struct _lt_stat_collection {
57*486c6fdaSRichard Lowe 	lt_stat_level_t lt_sc_level;
58*486c6fdaSRichard Lowe 	unsigned int lt_sc_id;
59*486c6fdaSRichard Lowe 	char *lt_sc_name;
60*486c6fdaSRichard Lowe 	lt_datagroup_t lt_sc_groups[NGROUPS];
61*486c6fdaSRichard Lowe 	/*
62*486c6fdaSRichard Lowe 	 * The following fields: lt_sc_parent, lt_sc_children and
63*486c6fdaSRichard Lowe 	 * lt_sc_check_child_func maintain the tree structure.
64*486c6fdaSRichard Lowe 	 */
65*486c6fdaSRichard Lowe 	lt_stat_collection_t *lt_sc_parent;		/* Parent node */
66*486c6fdaSRichard Lowe 	GHashTable *lt_sc_children;	/* pid/tid -> lt_stat_collection_t */
67*486c6fdaSRichard Lowe 	check_child_func_t lt_sc_check_child_func; /* Release dead children */
68*486c6fdaSRichard Lowe };
69*486c6fdaSRichard Lowe 
70*486c6fdaSRichard Lowe /* Internal data structure to back up a stat_list */
71*486c6fdaSRichard Lowe typedef struct _lt_stat_list lt_stat_list_t;
72*486c6fdaSRichard Lowe typedef void (*free_list_func_t)(lt_stat_list_t *);
73*486c6fdaSRichard Lowe struct _lt_stat_list {
74*486c6fdaSRichard Lowe 	int lt_sl_entry_count;
75*486c6fdaSRichard Lowe 	lt_stat_entry_t **lt_sl_entries;
76*486c6fdaSRichard Lowe 	uint64_t lt_sl_gtotal;
77*486c6fdaSRichard Lowe 	free_list_func_t lt_sl_free_func;
78*486c6fdaSRichard Lowe };
79*486c6fdaSRichard Lowe 
80*486c6fdaSRichard Lowe /* Root of the collection hierarchy: system level statistics */
81*486c6fdaSRichard Lowe static lt_stat_collection_t *stat_system = NULL;
82*486c6fdaSRichard Lowe 
83*486c6fdaSRichard Lowe /*
84*486c6fdaSRichard Lowe  * Data structure to hold synchronization objects.
85*486c6fdaSRichard Lowe  * We don't use normal "cause table" because this needs to be cleared
86*486c6fdaSRichard Lowe  * every time we refresh in order to make sure that stale synchronization
87*486c6fdaSRichard Lowe  * objects don't consume memory.
88*486c6fdaSRichard Lowe  */
89*486c6fdaSRichard Lowe typedef struct {
90*486c6fdaSRichard Lowe 	int lt_soi_type;
91*486c6fdaSRichard Lowe 	unsigned long long lt_soi_addr;
92*486c6fdaSRichard Lowe } lt_sobj_id_t;
93*486c6fdaSRichard Lowe 
94*486c6fdaSRichard Lowe typedef struct {
95*486c6fdaSRichard Lowe 	lt_sobj_id_t lt_so_oid;
96*486c6fdaSRichard Lowe 	int lt_so_cause_id;
97*486c6fdaSRichard Lowe 	char lt_so_string[32];	/* Enough to hold "%s: 0x%llX" */
98*486c6fdaSRichard Lowe } lt_sobj_t;
99*486c6fdaSRichard Lowe 
100*486c6fdaSRichard Lowe static GHashTable *sobj_table = NULL;
101*486c6fdaSRichard Lowe static int sobj_table_len = 0;
102*486c6fdaSRichard Lowe 
103*486c6fdaSRichard Lowe /*
104*486c6fdaSRichard Lowe  * Lower 32-bit of the address of synchronization objects is used to hash
105*486c6fdaSRichard Lowe  * them.
106*486c6fdaSRichard Lowe  */
107*486c6fdaSRichard Lowe static guint
sobj_id_hash(lt_sobj_id_t * id)108*486c6fdaSRichard Lowe sobj_id_hash(lt_sobj_id_t *id)
109*486c6fdaSRichard Lowe {
110*486c6fdaSRichard Lowe 	g_assert(id != NULL);
111*486c6fdaSRichard Lowe 	return (id->lt_soi_addr & 0xFFFFFFFF);
112*486c6fdaSRichard Lowe }
113*486c6fdaSRichard Lowe 
114*486c6fdaSRichard Lowe /*
115*486c6fdaSRichard Lowe  * Test if two synchronization objects are the same.
116*486c6fdaSRichard Lowe  */
117*486c6fdaSRichard Lowe static gboolean
sobj_id_equal(lt_sobj_id_t * a,lt_sobj_id_t * b)118*486c6fdaSRichard Lowe sobj_id_equal(lt_sobj_id_t *a, lt_sobj_id_t *b)
119*486c6fdaSRichard Lowe {
120*486c6fdaSRichard Lowe 	g_assert(a != NULL && b != NULL);
121*486c6fdaSRichard Lowe 	return (a->lt_soi_type == b->lt_soi_type &&
122*486c6fdaSRichard Lowe 	    a->lt_soi_addr == b->lt_soi_addr);
123*486c6fdaSRichard Lowe }
124*486c6fdaSRichard Lowe 
125*486c6fdaSRichard Lowe /*
126*486c6fdaSRichard Lowe  * Look up the cause_id of a synchronization object.
127*486c6fdaSRichard Lowe  * Note that this cause_id is only unique in GROUP_SOBJ, and changes after
128*486c6fdaSRichard Lowe  * a refresh.
129*486c6fdaSRichard Lowe  */
130*486c6fdaSRichard Lowe static lt_sobj_t *
lookup_sobj(lt_sobj_id_t * id)131*486c6fdaSRichard Lowe lookup_sobj(lt_sobj_id_t *id)
132*486c6fdaSRichard Lowe {
133*486c6fdaSRichard Lowe 	const char *stype_str[] = {
134*486c6fdaSRichard Lowe 		"None",
135*486c6fdaSRichard Lowe 		"Mutex",
136*486c6fdaSRichard Lowe 		"RWLock",
137*486c6fdaSRichard Lowe 		"CV",
138*486c6fdaSRichard Lowe 		"Sema",
139*486c6fdaSRichard Lowe 		"User",
140*486c6fdaSRichard Lowe 		"User_PI",
141*486c6fdaSRichard Lowe 		"Shuttle"
142*486c6fdaSRichard Lowe 	};
143*486c6fdaSRichard Lowe 	const int stype_str_len =
144*486c6fdaSRichard Lowe 	    sizeof (stype_str) / sizeof (stype_str[0]);
145*486c6fdaSRichard Lowe 	lt_sobj_t *ret = NULL;
146*486c6fdaSRichard Lowe 	g_assert(id != NULL);
147*486c6fdaSRichard Lowe 
148*486c6fdaSRichard Lowe 	if (id->lt_soi_type < 0 || id->lt_soi_type >= stype_str_len) {
149*486c6fdaSRichard Lowe 		return (NULL);
150*486c6fdaSRichard Lowe 	}
151*486c6fdaSRichard Lowe 
152*486c6fdaSRichard Lowe 	if (sobj_table != NULL) {
153*486c6fdaSRichard Lowe 		ret = (lt_sobj_t *)g_hash_table_lookup(sobj_table, id);
154*486c6fdaSRichard Lowe 	} else {
155*486c6fdaSRichard Lowe 		sobj_table = g_hash_table_new_full(
156*486c6fdaSRichard Lowe 		    (GHashFunc)sobj_id_hash, (GEqualFunc)sobj_id_equal,
157*486c6fdaSRichard Lowe 		    NULL, (GDestroyNotify)free);
158*486c6fdaSRichard Lowe 		lt_check_null(sobj_table);
159*486c6fdaSRichard Lowe 	}
160*486c6fdaSRichard Lowe 
161*486c6fdaSRichard Lowe 	if (ret == NULL) {
162*486c6fdaSRichard Lowe 		ret = (lt_sobj_t *)lt_zalloc(sizeof (lt_sobj_t));
163*486c6fdaSRichard Lowe 		ret->lt_so_cause_id = ++sobj_table_len;
164*486c6fdaSRichard Lowe 		(void) snprintf(ret->lt_so_string, sizeof (ret->lt_so_string),
165*486c6fdaSRichard Lowe 		    "%s: 0x%llX", stype_str[id->lt_soi_type], id->lt_soi_addr);
166*486c6fdaSRichard Lowe 		ret->lt_so_oid.lt_soi_type = id->lt_soi_type;
167*486c6fdaSRichard Lowe 		ret->lt_so_oid.lt_soi_addr = id->lt_soi_addr;
168*486c6fdaSRichard Lowe 
169*486c6fdaSRichard Lowe 		g_hash_table_insert(sobj_table, &ret->lt_so_oid, ret);
170*486c6fdaSRichard Lowe 	}
171*486c6fdaSRichard Lowe 
172*486c6fdaSRichard Lowe 	return (ret);
173*486c6fdaSRichard Lowe }
174*486c6fdaSRichard Lowe 
175*486c6fdaSRichard Lowe /*
176*486c6fdaSRichard Lowe  * Check if a process exists by using /proc/pid
177*486c6fdaSRichard Lowe  */
178*486c6fdaSRichard Lowe /* ARGSUSED */
179*486c6fdaSRichard Lowe static gboolean
check_process(gpointer key,lt_stat_collection_t * stat,void * user)180*486c6fdaSRichard Lowe check_process(gpointer key, lt_stat_collection_t *stat, void *user)
181*486c6fdaSRichard Lowe {
182*486c6fdaSRichard Lowe 	char name[PATH_MAX];
183*486c6fdaSRichard Lowe 
184*486c6fdaSRichard Lowe 	(void) snprintf(name, PATH_MAX, "/proc/%u", stat->lt_sc_id);
185*486c6fdaSRichard Lowe 	return (lt_file_exist(name) ? FALSE : TRUE);
186*486c6fdaSRichard Lowe }
187*486c6fdaSRichard Lowe 
188*486c6fdaSRichard Lowe /*
189*486c6fdaSRichard Lowe  * Check if a thread exists by using /proc/pid/lwp/tid
190*486c6fdaSRichard Lowe  */
191*486c6fdaSRichard Lowe /* ARGSUSED */
192*486c6fdaSRichard Lowe static gboolean
check_thread(gpointer key,lt_stat_collection_t * stat,void * user)193*486c6fdaSRichard Lowe check_thread(gpointer key, lt_stat_collection_t *stat, void *user)
194*486c6fdaSRichard Lowe {
195*486c6fdaSRichard Lowe 	char name[PATH_MAX];
196*486c6fdaSRichard Lowe 
197*486c6fdaSRichard Lowe 	g_assert(stat->lt_sc_parent != NULL);
198*486c6fdaSRichard Lowe 	g_assert(stat->lt_sc_parent->lt_sc_level == LT_LEVEL_PROCESS);
199*486c6fdaSRichard Lowe 
200*486c6fdaSRichard Lowe 	(void) snprintf(name, PATH_MAX, "/proc/%u/lwp/%u",
201*486c6fdaSRichard Lowe 	    stat->lt_sc_parent->lt_sc_id, stat->lt_sc_id);
202*486c6fdaSRichard Lowe 	return (lt_file_exist(name) ? FALSE : TRUE);
203*486c6fdaSRichard Lowe }
204*486c6fdaSRichard Lowe 
205*486c6fdaSRichard Lowe /*
206*486c6fdaSRichard Lowe  * Helper function to free a stat node.
207*486c6fdaSRichard Lowe  */
208*486c6fdaSRichard Lowe static void
free_stat(lt_stat_collection_t * stat)209*486c6fdaSRichard Lowe free_stat(lt_stat_collection_t *stat)
210*486c6fdaSRichard Lowe {
211*486c6fdaSRichard Lowe 	int i;
212*486c6fdaSRichard Lowe 
213*486c6fdaSRichard Lowe 	if (stat == NULL) {
214*486c6fdaSRichard Lowe 		return;
215*486c6fdaSRichard Lowe 	}
216*486c6fdaSRichard Lowe 
217*486c6fdaSRichard Lowe 	for (i = 0; i < NGROUPS; ++i) {
218*486c6fdaSRichard Lowe 		if (stat->lt_sc_groups[i].lt_grp_cidlist != NULL) {
219*486c6fdaSRichard Lowe 			g_hash_table_destroy(stat->lt_sc_groups[i].
220*486c6fdaSRichard Lowe 			    lt_grp_cidlist);
221*486c6fdaSRichard Lowe 		}
222*486c6fdaSRichard Lowe 	}
223*486c6fdaSRichard Lowe 
224*486c6fdaSRichard Lowe 	if (stat->lt_sc_children != NULL) {
225*486c6fdaSRichard Lowe 		g_hash_table_destroy(stat->lt_sc_children);
226*486c6fdaSRichard Lowe 	}
227*486c6fdaSRichard Lowe 
228*486c6fdaSRichard Lowe 	if (stat->lt_sc_name != NULL) {
229*486c6fdaSRichard Lowe 		free(stat->lt_sc_name);
230*486c6fdaSRichard Lowe 	}
231*486c6fdaSRichard Lowe 
232*486c6fdaSRichard Lowe 	free(stat);
233*486c6fdaSRichard Lowe }
234*486c6fdaSRichard Lowe 
235*486c6fdaSRichard Lowe /*
236*486c6fdaSRichard Lowe  * Helper function to initialize a stat node.
237*486c6fdaSRichard Lowe  */
238*486c6fdaSRichard Lowe /* ARGSUSED */
239*486c6fdaSRichard Lowe static void
clear_stat(gpointer key,lt_stat_collection_t * stat,void * user)240*486c6fdaSRichard Lowe clear_stat(gpointer key, lt_stat_collection_t *stat, void *user)
241*486c6fdaSRichard Lowe {
242*486c6fdaSRichard Lowe 	int i;
243*486c6fdaSRichard Lowe 
244*486c6fdaSRichard Lowe 	g_assert(stat != NULL);
245*486c6fdaSRichard Lowe 
246*486c6fdaSRichard Lowe 	for (i = 0; i < NGROUPS; ++i) {
247*486c6fdaSRichard Lowe 		if (stat->lt_sc_groups[i].lt_grp_cidlist != NULL) {
248*486c6fdaSRichard Lowe 			g_hash_table_destroy(stat->lt_sc_groups[i].
249*486c6fdaSRichard Lowe 			    lt_grp_cidlist);
250*486c6fdaSRichard Lowe 			stat->lt_sc_groups[i].lt_grp_cidlist = NULL;
251*486c6fdaSRichard Lowe 		}
252*486c6fdaSRichard Lowe 
253*486c6fdaSRichard Lowe 		stat->lt_sc_groups[i].lt_grp_summary.lt_se_data.lt_s_count = 0;
254*486c6fdaSRichard Lowe 		stat->lt_sc_groups[i].lt_grp_summary.lt_se_data.lt_s_total = 0;
255*486c6fdaSRichard Lowe 		stat->lt_sc_groups[i].lt_grp_summary.lt_se_data.lt_s_max = 0;
256*486c6fdaSRichard Lowe 	}
257*486c6fdaSRichard Lowe 
258*486c6fdaSRichard Lowe 	if (stat->lt_sc_children != NULL) {
259*486c6fdaSRichard Lowe 		g_hash_table_foreach_remove(stat->lt_sc_children,
260*486c6fdaSRichard Lowe 		    (GHRFunc)stat->lt_sc_check_child_func, NULL);
261*486c6fdaSRichard Lowe 		g_hash_table_foreach(stat->lt_sc_children,
262*486c6fdaSRichard Lowe 		    (GHFunc)clear_stat, NULL);
263*486c6fdaSRichard Lowe 	}
264*486c6fdaSRichard Lowe }
265*486c6fdaSRichard Lowe 
266*486c6fdaSRichard Lowe /*
267*486c6fdaSRichard Lowe  * Update a collection with the given value.
268*486c6fdaSRichard Lowe  * Recursively update parents in the hierarchy  until the root is reached.
269*486c6fdaSRichard Lowe  */
270*486c6fdaSRichard Lowe static void
update_stat_entry(lt_stat_collection_t * stat,int cause_id,lt_stat_type_t type,uint64_t value,const char * string,int group_to_use)271*486c6fdaSRichard Lowe update_stat_entry(lt_stat_collection_t *stat, int cause_id,
272*486c6fdaSRichard Lowe     lt_stat_type_t type, uint64_t value,
273*486c6fdaSRichard Lowe     const char *string, int group_to_use)
274*486c6fdaSRichard Lowe {
275*486c6fdaSRichard Lowe 	lt_stat_entry_t *entry = NULL;
276*486c6fdaSRichard Lowe 	lt_datagroup_t *group;
277*486c6fdaSRichard Lowe 
278*486c6fdaSRichard Lowe 	if (group_to_use < 0 || group_to_use >= NGROUPS) {
279*486c6fdaSRichard Lowe 		return;
280*486c6fdaSRichard Lowe 	}
281*486c6fdaSRichard Lowe 
282*486c6fdaSRichard Lowe 	group = &(stat->lt_sc_groups[group_to_use]);
283*486c6fdaSRichard Lowe 
284*486c6fdaSRichard Lowe 	if (group->lt_grp_cidlist != NULL) {
285*486c6fdaSRichard Lowe 		entry = (lt_stat_entry_t *)g_hash_table_lookup(
286*486c6fdaSRichard Lowe 		    group->lt_grp_cidlist, LT_INT_TO_POINTER(cause_id));
287*486c6fdaSRichard Lowe 	} else   {
288*486c6fdaSRichard Lowe 		group->lt_grp_cidlist = g_hash_table_new_full(
289*486c6fdaSRichard Lowe 		    g_direct_hash, g_direct_equal,
290*486c6fdaSRichard Lowe 		    NULL, (GDestroyNotify)free);
291*486c6fdaSRichard Lowe 		lt_check_null(group->lt_grp_cidlist);
292*486c6fdaSRichard Lowe 	}
293*486c6fdaSRichard Lowe 
294*486c6fdaSRichard Lowe 	if (entry == NULL) {
295*486c6fdaSRichard Lowe 		entry = (lt_stat_entry_t *)lt_zalloc(sizeof (lt_stat_entry_t));
296*486c6fdaSRichard Lowe 		entry->lt_se_string = string;
297*486c6fdaSRichard Lowe 
298*486c6fdaSRichard Lowe 		switch (group_to_use) {
299*486c6fdaSRichard Lowe 		case GROUP_CAUSE:
300*486c6fdaSRichard Lowe 			entry->lt_se_type = STAT_CAUSE;
301*486c6fdaSRichard Lowe 			entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_id = cause_id;
302*486c6fdaSRichard Lowe 			entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags =
303*486c6fdaSRichard Lowe 			    lt_table_get_cause_flag(cause_id, CAUSE_ALL_FLAGS);
304*486c6fdaSRichard Lowe 
305*486c6fdaSRichard Lowe 			/* hide the first '#' */
306*486c6fdaSRichard Lowe 			if ((entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags
307*486c6fdaSRichard Lowe 			    & CAUSE_FLAG_HIDE_IN_SUMMARY) != 0) {
308*486c6fdaSRichard Lowe 				++entry->lt_se_string;
309*486c6fdaSRichard Lowe 			}
310*486c6fdaSRichard Lowe 
311*486c6fdaSRichard Lowe 			break;
312*486c6fdaSRichard Lowe 		case GROUP_SOBJ:
313*486c6fdaSRichard Lowe 			entry->lt_se_type = STAT_SOBJ;
314*486c6fdaSRichard Lowe 			entry->lt_se_tsdata.lt_se_t_sobj.lt_se_s_id = cause_id;
315*486c6fdaSRichard Lowe 			break;
316*486c6fdaSRichard Lowe 		}
317*486c6fdaSRichard Lowe 
318*486c6fdaSRichard Lowe 		g_hash_table_insert(group->lt_grp_cidlist,
319*486c6fdaSRichard Lowe 		    LT_INT_TO_POINTER(cause_id), entry);
320*486c6fdaSRichard Lowe 	}
321*486c6fdaSRichard Lowe 
322*486c6fdaSRichard Lowe 	lt_update_stat_value(&entry->lt_se_data, type, value);
323*486c6fdaSRichard Lowe 
324*486c6fdaSRichard Lowe 	if (group_to_use == GROUP_SOBJ ||
325*486c6fdaSRichard Lowe 	    (entry->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags &
326*486c6fdaSRichard Lowe 	    CAUSE_FLAG_HIDE_IN_SUMMARY) == 0) {
327*486c6fdaSRichard Lowe 		lt_update_stat_value(&group->lt_grp_summary.lt_se_data, type,
328*486c6fdaSRichard Lowe 		    value);
329*486c6fdaSRichard Lowe 	}
330*486c6fdaSRichard Lowe 
331*486c6fdaSRichard Lowe 	if (stat->lt_sc_parent != NULL) {
332*486c6fdaSRichard Lowe 		update_stat_entry(stat->lt_sc_parent, cause_id, type, value,
333*486c6fdaSRichard Lowe 		    string, group_to_use);
334*486c6fdaSRichard Lowe 	}
335*486c6fdaSRichard Lowe }
336*486c6fdaSRichard Lowe 
337*486c6fdaSRichard Lowe /*
338*486c6fdaSRichard Lowe  * Identify the cause of latency from the given stack trace.
339*486c6fdaSRichard Lowe  * Return cause_id.
340*486c6fdaSRichard Lowe  */
341*486c6fdaSRichard Lowe static void
find_cause(char * stack,int * cause_id,int * cause_priority)342*486c6fdaSRichard Lowe find_cause(char *stack, int *cause_id, int *cause_priority)
343*486c6fdaSRichard Lowe {
344*486c6fdaSRichard Lowe 	int cause_temp;
345*486c6fdaSRichard Lowe 	int prio_temp;
346*486c6fdaSRichard Lowe 	int cause = INVALID_CAUSE;
347*486c6fdaSRichard Lowe 	int priority = 0;
348*486c6fdaSRichard Lowe 	int found = 0;
349*486c6fdaSRichard Lowe 
350*486c6fdaSRichard Lowe 	g_assert(cause_id != NULL);
351*486c6fdaSRichard Lowe 	g_assert(cause_priority != NULL);
352*486c6fdaSRichard Lowe 
353*486c6fdaSRichard Lowe 	while (stack != NULL) {
354*486c6fdaSRichard Lowe 		char *sep;
355*486c6fdaSRichard Lowe 		sep = strchr(stack, ' ');
356*486c6fdaSRichard Lowe 
357*486c6fdaSRichard Lowe 		if (sep != NULL) {
358*486c6fdaSRichard Lowe 			*sep = '\0';
359*486c6fdaSRichard Lowe 		}
360*486c6fdaSRichard Lowe 
361*486c6fdaSRichard Lowe 		found = lt_table_cause_from_stack(stack, &cause_temp,
362*486c6fdaSRichard Lowe 		    &prio_temp);
363*486c6fdaSRichard Lowe 
364*486c6fdaSRichard Lowe 		if (found && (cause == INVALID_CAUSE ||
365*486c6fdaSRichard Lowe 		    HIGHER_PRIORITY(prio_temp, priority))) {
366*486c6fdaSRichard Lowe 			cause = cause_temp;
367*486c6fdaSRichard Lowe 			priority = prio_temp;
368*486c6fdaSRichard Lowe 		}
369*486c6fdaSRichard Lowe 
370*486c6fdaSRichard Lowe 		if (sep != NULL) {
371*486c6fdaSRichard Lowe 			*sep = ' ';
372*486c6fdaSRichard Lowe 			stack = sep + 1;
373*486c6fdaSRichard Lowe 		} else   {
374*486c6fdaSRichard Lowe 			stack = NULL;
375*486c6fdaSRichard Lowe 		}
376*486c6fdaSRichard Lowe 	}
377*486c6fdaSRichard Lowe 
378*486c6fdaSRichard Lowe 	*cause_id = cause;
379*486c6fdaSRichard Lowe 	*cause_priority = priority;
380*486c6fdaSRichard Lowe }
381*486c6fdaSRichard Lowe 
382*486c6fdaSRichard Lowe /*
383*486c6fdaSRichard Lowe  * Create a new collection and hook it to the parent.
384*486c6fdaSRichard Lowe  */
385*486c6fdaSRichard Lowe static lt_stat_collection_t *
new_collection(lt_stat_level_t level,unsigned int id,char * name,lt_stat_collection_t * parent,check_child_func_t check_child_func)386*486c6fdaSRichard Lowe new_collection(lt_stat_level_t level, unsigned int id, char *name,
387*486c6fdaSRichard Lowe     lt_stat_collection_t *parent, check_child_func_t check_child_func)
388*486c6fdaSRichard Lowe {
389*486c6fdaSRichard Lowe 	int i;
390*486c6fdaSRichard Lowe 	lt_stat_collection_t *ret;
391*486c6fdaSRichard Lowe 
392*486c6fdaSRichard Lowe 	ret = (lt_stat_collection_t *)
393*486c6fdaSRichard Lowe 	    lt_zalloc(sizeof (lt_stat_collection_t));
394*486c6fdaSRichard Lowe 
395*486c6fdaSRichard Lowe 	ret->lt_sc_level = level;
396*486c6fdaSRichard Lowe 	ret->lt_sc_check_child_func = check_child_func;
397*486c6fdaSRichard Lowe 	ret->lt_sc_id = id;
398*486c6fdaSRichard Lowe 	ret->lt_sc_name = name;
399*486c6fdaSRichard Lowe 
400*486c6fdaSRichard Lowe 	for (i = 0; i < NGROUPS; ++i) {
401*486c6fdaSRichard Lowe 		ret->lt_sc_groups[i].lt_grp_summary.lt_se_string =
402*486c6fdaSRichard Lowe 		    (const char *)name;
403*486c6fdaSRichard Lowe 	}
404*486c6fdaSRichard Lowe 
405*486c6fdaSRichard Lowe 	if (parent != NULL) {
406*486c6fdaSRichard Lowe 		ret->lt_sc_parent = parent;
407*486c6fdaSRichard Lowe 
408*486c6fdaSRichard Lowe 		if (parent->lt_sc_children == NULL) {
409*486c6fdaSRichard Lowe 			parent->lt_sc_children = g_hash_table_new_full(
410*486c6fdaSRichard Lowe 			    g_direct_hash, g_direct_equal,
411*486c6fdaSRichard Lowe 			    NULL, (GDestroyNotify)free_stat);
412*486c6fdaSRichard Lowe 			lt_check_null(parent->lt_sc_children);
413*486c6fdaSRichard Lowe 		}
414*486c6fdaSRichard Lowe 
415*486c6fdaSRichard Lowe 		g_hash_table_insert(parent->lt_sc_children,
416*486c6fdaSRichard Lowe 		    LT_INT_TO_POINTER((int)id), ret);
417*486c6fdaSRichard Lowe 	}
418*486c6fdaSRichard Lowe 
419*486c6fdaSRichard Lowe 	return (ret);
420*486c6fdaSRichard Lowe }
421*486c6fdaSRichard Lowe 
422*486c6fdaSRichard Lowe /*
423*486c6fdaSRichard Lowe  * Find the "leaf" in the collection hierarchy, using the given pid and tid.
424*486c6fdaSRichard Lowe  */
425*486c6fdaSRichard Lowe static lt_stat_collection_t *
get_stat_c(pid_t pid,id_t tid)426*486c6fdaSRichard Lowe get_stat_c(pid_t pid, id_t tid)
427*486c6fdaSRichard Lowe {
428*486c6fdaSRichard Lowe 	lt_stat_collection_t *stat_p = NULL;
429*486c6fdaSRichard Lowe 	lt_stat_collection_t *stat_t = NULL;
430*486c6fdaSRichard Lowe 
431*486c6fdaSRichard Lowe 	if (stat_system == NULL) {
432*486c6fdaSRichard Lowe 		stat_system = new_collection(LT_LEVEL_GLOBAL,
433*486c6fdaSRichard Lowe 		    PID_SYS_GLOBAL, lt_strdup("SYSTEM"), NULL, check_process);
434*486c6fdaSRichard Lowe 	} else if (stat_system->lt_sc_children != NULL) {
435*486c6fdaSRichard Lowe 		stat_p = (lt_stat_collection_t *)
436*486c6fdaSRichard Lowe 		    g_hash_table_lookup(stat_system->lt_sc_children,
437*486c6fdaSRichard Lowe 		    LT_INT_TO_POINTER(pid));
438*486c6fdaSRichard Lowe 	}
439*486c6fdaSRichard Lowe 
440*486c6fdaSRichard Lowe 	if (stat_p == NULL) {
441*486c6fdaSRichard Lowe 		char *fname;
442*486c6fdaSRichard Lowe 		fname = lt_get_proc_field(pid, LT_FIELD_FNAME);
443*486c6fdaSRichard Lowe 
444*486c6fdaSRichard Lowe 		if (fname == NULL) {
445*486c6fdaSRichard Lowe 			/*
446*486c6fdaSRichard Lowe 			 * we could not get the executable name of the
447*486c6fdaSRichard Lowe 			 * process; the process is probably already dead.
448*486c6fdaSRichard Lowe 			 */
449*486c6fdaSRichard Lowe 			return (NULL);
450*486c6fdaSRichard Lowe 		}
451*486c6fdaSRichard Lowe 
452*486c6fdaSRichard Lowe 		stat_p = new_collection(LT_LEVEL_PROCESS,
453*486c6fdaSRichard Lowe 		    (unsigned int)pid, fname, stat_system, check_thread);
454*486c6fdaSRichard Lowe 	} else if (stat_p->lt_sc_children != NULL) {
455*486c6fdaSRichard Lowe 		stat_t = (lt_stat_collection_t *)
456*486c6fdaSRichard Lowe 		    g_hash_table_lookup(stat_p->lt_sc_children,
457*486c6fdaSRichard Lowe 		    LT_INT_TO_POINTER(tid));
458*486c6fdaSRichard Lowe 	}
459*486c6fdaSRichard Lowe 
460*486c6fdaSRichard Lowe 	if (stat_t == NULL) {
461*486c6fdaSRichard Lowe 		const int tname_size = 16; /* Enough for "Thread %d" */
462*486c6fdaSRichard Lowe 		char *tname;
463*486c6fdaSRichard Lowe 
464*486c6fdaSRichard Lowe 		tname = (char *)lt_zalloc(tname_size);
465*486c6fdaSRichard Lowe 		(void) snprintf(tname, tname_size, "Thread %d", tid);
466*486c6fdaSRichard Lowe 
467*486c6fdaSRichard Lowe 		stat_t = new_collection(LT_LEVEL_THREAD,
468*486c6fdaSRichard Lowe 		    (unsigned int)tid, tname, stat_p, NULL);
469*486c6fdaSRichard Lowe 	}
470*486c6fdaSRichard Lowe 
471*486c6fdaSRichard Lowe 	return (stat_t);
472*486c6fdaSRichard Lowe }
473*486c6fdaSRichard Lowe 
474*486c6fdaSRichard Lowe /*
475*486c6fdaSRichard Lowe  * Update statistics with the given cause_id. Values will be added to
476*486c6fdaSRichard Lowe  * internal statistics.
477*486c6fdaSRichard Lowe  */
478*486c6fdaSRichard Lowe void
lt_stat_update_cause(pid_t pid,id_t tid,int cause_id,lt_stat_type_t type,uint64_t value)479*486c6fdaSRichard Lowe lt_stat_update_cause(pid_t pid, id_t tid, int cause_id, lt_stat_type_t type,
480*486c6fdaSRichard Lowe     uint64_t value)
481*486c6fdaSRichard Lowe {
482*486c6fdaSRichard Lowe 	const char *string;
483*486c6fdaSRichard Lowe 	lt_stat_collection_t *stat_t = NULL;
484*486c6fdaSRichard Lowe 
485*486c6fdaSRichard Lowe 	if (cause_id < 0 || value == 0) {
486*486c6fdaSRichard Lowe 		return;
487*486c6fdaSRichard Lowe 	}
488*486c6fdaSRichard Lowe 
489*486c6fdaSRichard Lowe 	if (lt_table_get_cause_flag(cause_id, CAUSE_FLAG_DISABLED)) {
490*486c6fdaSRichard Lowe 		/* Ignore this cause */
491*486c6fdaSRichard Lowe 		return;
492*486c6fdaSRichard Lowe 	}
493*486c6fdaSRichard Lowe 
494*486c6fdaSRichard Lowe 	stat_t = get_stat_c(pid, tid);
495*486c6fdaSRichard Lowe 
496*486c6fdaSRichard Lowe 	if (stat_t == NULL) {
497*486c6fdaSRichard Lowe 		/* Process must be dead. */
498*486c6fdaSRichard Lowe 		return;
499*486c6fdaSRichard Lowe 	}
500*486c6fdaSRichard Lowe 
501*486c6fdaSRichard Lowe 	string = lt_table_get_cause_name(cause_id);
502*486c6fdaSRichard Lowe 
503*486c6fdaSRichard Lowe 	update_stat_entry(stat_t, cause_id, type, value, string, GROUP_CAUSE);
504*486c6fdaSRichard Lowe }
505*486c6fdaSRichard Lowe 
506*486c6fdaSRichard Lowe /*
507*486c6fdaSRichard Lowe  * Update statistics with the given stack trace.
508*486c6fdaSRichard Lowe  * The stack trace is mapped to a cause and lt_stat_update_cause() is called
509*486c6fdaSRichard Lowe  * to update statistics.
510*486c6fdaSRichard Lowe  */
511*486c6fdaSRichard Lowe void
lt_stat_update(pid_t pid,id_t tid,char * stack,char * tag,unsigned int tag_priority,lt_stat_type_t type,uint64_t value)512*486c6fdaSRichard Lowe lt_stat_update(pid_t pid, id_t tid, char *stack, char *tag,
513*486c6fdaSRichard Lowe     unsigned int tag_priority, lt_stat_type_t type, uint64_t value)
514*486c6fdaSRichard Lowe {
515*486c6fdaSRichard Lowe 	int tag_cause_id = INVALID_CAUSE;
516*486c6fdaSRichard Lowe 	int stack_cause_id = INVALID_CAUSE;
517*486c6fdaSRichard Lowe 	int cause_id = INVALID_CAUSE;
518*486c6fdaSRichard Lowe 	int stack_priority = 0;
519*486c6fdaSRichard Lowe 
520*486c6fdaSRichard Lowe 	if (value == 0) {
521*486c6fdaSRichard Lowe 		return;
522*486c6fdaSRichard Lowe 	}
523*486c6fdaSRichard Lowe 
524*486c6fdaSRichard Lowe 	find_cause(stack, &stack_cause_id, &stack_priority);
525*486c6fdaSRichard Lowe 
526*486c6fdaSRichard Lowe 	if (tag_priority != 0) {
527*486c6fdaSRichard Lowe 		tag_cause_id = lt_table_cause_from_name(tag, 0, 0);
528*486c6fdaSRichard Lowe 
529*486c6fdaSRichard Lowe 		if (tag_cause_id == INVALID_CAUSE) {
530*486c6fdaSRichard Lowe 			/* This must be a syscall tag */
531*486c6fdaSRichard Lowe 			char tmp[64];
532*486c6fdaSRichard Lowe 			(void) snprintf(tmp, sizeof (tmp), "Syscall: %s", tag);
533*486c6fdaSRichard Lowe 			tag_cause_id = lt_table_cause_from_name(tmp, 1, 0);
534*486c6fdaSRichard Lowe 		}
535*486c6fdaSRichard Lowe 	}
536*486c6fdaSRichard Lowe 
537*486c6fdaSRichard Lowe 	cause_id = (tag_priority > stack_priority) ? tag_cause_id :
538*486c6fdaSRichard Lowe 	    stack_cause_id;
539*486c6fdaSRichard Lowe 
540*486c6fdaSRichard Lowe 	if (cause_id == INVALID_CAUSE) {
541*486c6fdaSRichard Lowe 		/*
542*486c6fdaSRichard Lowe 		 * We got an unmapped stack. Set SPECIAL flag to display it
543*486c6fdaSRichard Lowe 		 * in pane 2. This makes it easier to find the cause.
544*486c6fdaSRichard Lowe 		 */
545*486c6fdaSRichard Lowe 		cause_id = lt_table_cause_from_name(stack, 1,
546*486c6fdaSRichard Lowe 		    CAUSE_FLAG_SPECIAL);
547*486c6fdaSRichard Lowe 		lt_klog_log(LT_KLOG_LEVEL_UNMAPPED, pid, stack, type, value);
548*486c6fdaSRichard Lowe 	} else   {
549*486c6fdaSRichard Lowe 		lt_klog_log(LT_KLOG_LEVEL_MAPPED, pid, stack, type, value);
550*486c6fdaSRichard Lowe 	}
551*486c6fdaSRichard Lowe 
552*486c6fdaSRichard Lowe 	lt_stat_update_cause(pid, tid, cause_id, type, value);
553*486c6fdaSRichard Lowe }
554*486c6fdaSRichard Lowe 
555*486c6fdaSRichard Lowe /*
556*486c6fdaSRichard Lowe  * Zero out all statistics, but keep the data structures in memory
557*486c6fdaSRichard Lowe  * to be used to hold new data immediately following.
558*486c6fdaSRichard Lowe  */
559*486c6fdaSRichard Lowe void
lt_stat_clear_all(void)560*486c6fdaSRichard Lowe lt_stat_clear_all(void)
561*486c6fdaSRichard Lowe {
562*486c6fdaSRichard Lowe 	if (stat_system != NULL) {
563*486c6fdaSRichard Lowe 		clear_stat(NULL, stat_system, NULL);
564*486c6fdaSRichard Lowe 	}
565*486c6fdaSRichard Lowe 
566*486c6fdaSRichard Lowe 	if (sobj_table != NULL) {
567*486c6fdaSRichard Lowe 		g_hash_table_destroy(sobj_table);
568*486c6fdaSRichard Lowe 		sobj_table = NULL;
569*486c6fdaSRichard Lowe 	}
570*486c6fdaSRichard Lowe }
571*486c6fdaSRichard Lowe 
572*486c6fdaSRichard Lowe /*
573*486c6fdaSRichard Lowe  * Clean up function that frees all memory used for statistics.
574*486c6fdaSRichard Lowe  */
575*486c6fdaSRichard Lowe void
lt_stat_free_all(void)576*486c6fdaSRichard Lowe lt_stat_free_all(void)
577*486c6fdaSRichard Lowe {
578*486c6fdaSRichard Lowe 	if (stat_system != NULL) {
579*486c6fdaSRichard Lowe 		free_stat(stat_system);
580*486c6fdaSRichard Lowe 		stat_system = NULL;
581*486c6fdaSRichard Lowe 	}
582*486c6fdaSRichard Lowe 
583*486c6fdaSRichard Lowe 	if (sobj_table != NULL) {
584*486c6fdaSRichard Lowe 		g_hash_table_destroy(sobj_table);
585*486c6fdaSRichard Lowe 		sobj_table = NULL;
586*486c6fdaSRichard Lowe 	}
587*486c6fdaSRichard Lowe }
588*486c6fdaSRichard Lowe 
589*486c6fdaSRichard Lowe /*
590*486c6fdaSRichard Lowe  * Get top N causes of latency for a process. Return handle to a stat_list.
591*486c6fdaSRichard Lowe  * Use pid = PID_SYS_GLOBAL to get global top list.
592*486c6fdaSRichard Lowe  * Call lt_stat_list_free after use to clean up.
593*486c6fdaSRichard Lowe  */
594*486c6fdaSRichard Lowe void *
lt_stat_list_create(lt_list_type_t list_type,lt_stat_level_t level,pid_t pid,id_t tid,int count,lt_sort_t sort_by)595*486c6fdaSRichard Lowe lt_stat_list_create(lt_list_type_t list_type, lt_stat_level_t level,
596*486c6fdaSRichard Lowe     pid_t pid, id_t tid, int count, lt_sort_t sort_by)
597*486c6fdaSRichard Lowe {
598*486c6fdaSRichard Lowe 	GCompareFunc func;
599*486c6fdaSRichard Lowe 	GList *list, *walk;
600*486c6fdaSRichard Lowe 	lt_stat_collection_t *stat_c = NULL;
601*486c6fdaSRichard Lowe 	lt_stat_list_t *ret;
602*486c6fdaSRichard Lowe 	lt_datagroup_t *group;
603*486c6fdaSRichard Lowe 
604*486c6fdaSRichard Lowe 	if (level == LT_LEVEL_GLOBAL) {
605*486c6fdaSRichard Lowe 		/* Use global entry */
606*486c6fdaSRichard Lowe 		stat_c = stat_system;
607*486c6fdaSRichard Lowe 	} else if (stat_system != NULL && stat_system->lt_sc_children != NULL) {
608*486c6fdaSRichard Lowe 		/* Find process entry first */
609*486c6fdaSRichard Lowe 		stat_c = (lt_stat_collection_t *)g_hash_table_lookup(
610*486c6fdaSRichard Lowe 		    stat_system->lt_sc_children, LT_INT_TO_POINTER(pid));
611*486c6fdaSRichard Lowe 
612*486c6fdaSRichard Lowe 		if (level == LT_LEVEL_THREAD) {
613*486c6fdaSRichard Lowe 			/*
614*486c6fdaSRichard Lowe 			 * If thread entry is requested, find it based on
615*486c6fdaSRichard Lowe 			 * process entry.
616*486c6fdaSRichard Lowe 			 */
617*486c6fdaSRichard Lowe 			if (stat_c != NULL && stat_c->lt_sc_children != NULL) {
618*486c6fdaSRichard Lowe 				stat_c = (lt_stat_collection_t *)
619*486c6fdaSRichard Lowe 				    g_hash_table_lookup(stat_c->lt_sc_children,
620*486c6fdaSRichard Lowe 				    LT_INT_TO_POINTER(tid));
621*486c6fdaSRichard Lowe 			} else {
622*486c6fdaSRichard Lowe 				/*
623*486c6fdaSRichard Lowe 				 * Thread entry was not found; set it to NULL,
624*486c6fdaSRichard Lowe 				 * so that we can return empty list later.
625*486c6fdaSRichard Lowe 				 */
626*486c6fdaSRichard Lowe 				stat_c = NULL;
627*486c6fdaSRichard Lowe 			}
628*486c6fdaSRichard Lowe 		}
629*486c6fdaSRichard Lowe 	}
630*486c6fdaSRichard Lowe 
631*486c6fdaSRichard Lowe 	ret = (lt_stat_list_t *)lt_zalloc(sizeof (lt_stat_list_t));
632*486c6fdaSRichard Lowe 	ret->lt_sl_entries = (lt_stat_entry_t **)
633*486c6fdaSRichard Lowe 	    lt_zalloc(count * sizeof (lt_stat_entry_t *));
634*486c6fdaSRichard Lowe 
635*486c6fdaSRichard Lowe 	if (stat_c == NULL) {
636*486c6fdaSRichard Lowe 		/* Empty list */
637*486c6fdaSRichard Lowe 		return (ret);
638*486c6fdaSRichard Lowe 	}
639*486c6fdaSRichard Lowe 
640*486c6fdaSRichard Lowe 	if (list_type == LT_LIST_SOBJ) {
641*486c6fdaSRichard Lowe 		group = &(stat_c->lt_sc_groups[GROUP_SOBJ]);
642*486c6fdaSRichard Lowe 	} else {
643*486c6fdaSRichard Lowe 		group = &(stat_c->lt_sc_groups[GROUP_CAUSE]);
644*486c6fdaSRichard Lowe 	}
645*486c6fdaSRichard Lowe 
646*486c6fdaSRichard Lowe 	if (group->lt_grp_cidlist == NULL) {
647*486c6fdaSRichard Lowe 		/* Empty list */
648*486c6fdaSRichard Lowe 		return (ret);
649*486c6fdaSRichard Lowe 	}
650*486c6fdaSRichard Lowe 
651*486c6fdaSRichard Lowe 	ret->lt_sl_gtotal = group->lt_grp_summary.lt_se_data.lt_s_total;
652*486c6fdaSRichard Lowe 
653*486c6fdaSRichard Lowe 	list = g_hash_table_get_values(group->lt_grp_cidlist);
654*486c6fdaSRichard Lowe 
655*486c6fdaSRichard Lowe 	switch (sort_by) {
656*486c6fdaSRichard Lowe 	case LT_SORT_TOTAL:
657*486c6fdaSRichard Lowe 		func = (GCompareFunc)lt_sort_by_total_desc;
658*486c6fdaSRichard Lowe 		break;
659*486c6fdaSRichard Lowe 	case LT_SORT_MAX:
660*486c6fdaSRichard Lowe 		func = (GCompareFunc)lt_sort_by_max_desc;
661*486c6fdaSRichard Lowe 		break;
662*486c6fdaSRichard Lowe 	case LT_SORT_AVG:
663*486c6fdaSRichard Lowe 		func = (GCompareFunc)lt_sort_by_avg_desc;
664*486c6fdaSRichard Lowe 		break;
665*486c6fdaSRichard Lowe 	case LT_SORT_COUNT:
666*486c6fdaSRichard Lowe 		func = (GCompareFunc)lt_sort_by_count_desc;
667*486c6fdaSRichard Lowe 		break;
668*486c6fdaSRichard Lowe 	}
669*486c6fdaSRichard Lowe 	list = g_list_sort(list, func);
670*486c6fdaSRichard Lowe 
671*486c6fdaSRichard Lowe 	for (walk = list;
672*486c6fdaSRichard Lowe 	    walk != NULL && count > 0;
673*486c6fdaSRichard Lowe 	    walk = g_list_next(walk), --count) {
674*486c6fdaSRichard Lowe 		lt_stat_entry_t *data = (lt_stat_entry_t *)walk->data;
675*486c6fdaSRichard Lowe 
676*486c6fdaSRichard Lowe 		if (list_type == LT_LIST_CAUSE &&
677*486c6fdaSRichard Lowe 		    data->lt_se_type == STAT_CAUSE &&
678*486c6fdaSRichard Lowe 		    (data->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags &
679*486c6fdaSRichard Lowe 		    CAUSE_FLAG_HIDE_IN_SUMMARY) != 0) {
680*486c6fdaSRichard Lowe 			continue;
681*486c6fdaSRichard Lowe 		}
682*486c6fdaSRichard Lowe 
683*486c6fdaSRichard Lowe 		if (list_type == LT_LIST_SPECIALS &&
684*486c6fdaSRichard Lowe 		    data->lt_se_type == STAT_CAUSE &&
685*486c6fdaSRichard Lowe 		    (data->lt_se_tsdata.lt_se_t_cause.lt_se_c_flags &
686*486c6fdaSRichard Lowe 		    CAUSE_FLAG_SPECIAL) == 0) {
687*486c6fdaSRichard Lowe 			continue;
688*486c6fdaSRichard Lowe 		}
689*486c6fdaSRichard Lowe 
690*486c6fdaSRichard Lowe 		if (data->lt_se_data.lt_s_count == 0) {
691*486c6fdaSRichard Lowe 			break;
692*486c6fdaSRichard Lowe 		}
693*486c6fdaSRichard Lowe 
694*486c6fdaSRichard Lowe 		ret->lt_sl_entries[ret->lt_sl_entry_count++] = data;
695*486c6fdaSRichard Lowe 	}
696*486c6fdaSRichard Lowe 
697*486c6fdaSRichard Lowe 	g_list_free(list);
698*486c6fdaSRichard Lowe 
699*486c6fdaSRichard Lowe 	return (ret);
700*486c6fdaSRichard Lowe }
701*486c6fdaSRichard Lowe 
702*486c6fdaSRichard Lowe /*
703*486c6fdaSRichard Lowe  * Free memory allocated by lt_stat_list_create().
704*486c6fdaSRichard Lowe  */
705*486c6fdaSRichard Lowe void
lt_stat_list_free(void * ptr)706*486c6fdaSRichard Lowe lt_stat_list_free(void *ptr)
707*486c6fdaSRichard Lowe {
708*486c6fdaSRichard Lowe 	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
709*486c6fdaSRichard Lowe 
710*486c6fdaSRichard Lowe 	if (list == NULL) {
711*486c6fdaSRichard Lowe 		return;
712*486c6fdaSRichard Lowe 	}
713*486c6fdaSRichard Lowe 
714*486c6fdaSRichard Lowe 	if (list->lt_sl_free_func != NULL) {
715*486c6fdaSRichard Lowe 		list->lt_sl_free_func(list);
716*486c6fdaSRichard Lowe 	}
717*486c6fdaSRichard Lowe 
718*486c6fdaSRichard Lowe 	if (list->lt_sl_entries != NULL) {
719*486c6fdaSRichard Lowe 		free(list->lt_sl_entries);
720*486c6fdaSRichard Lowe 	}
721*486c6fdaSRichard Lowe 
722*486c6fdaSRichard Lowe 	free(list);
723*486c6fdaSRichard Lowe }
724*486c6fdaSRichard Lowe 
725*486c6fdaSRichard Lowe /*
726*486c6fdaSRichard Lowe  * Check if the given list contains the given item.
727*486c6fdaSRichard Lowe  */
728*486c6fdaSRichard Lowe int
lt_stat_list_has_item(void * ptr,int i)729*486c6fdaSRichard Lowe lt_stat_list_has_item(void *ptr, int i)
730*486c6fdaSRichard Lowe {
731*486c6fdaSRichard Lowe 	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
732*486c6fdaSRichard Lowe 
733*486c6fdaSRichard Lowe 	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
734*486c6fdaSRichard Lowe 	    list->lt_sl_entries[i] == NULL) {
735*486c6fdaSRichard Lowe 		return (0);
736*486c6fdaSRichard Lowe 	}
737*486c6fdaSRichard Lowe 
738*486c6fdaSRichard Lowe 	return (1);
739*486c6fdaSRichard Lowe }
740*486c6fdaSRichard Lowe 
741*486c6fdaSRichard Lowe /*
742*486c6fdaSRichard Lowe  * Get display name of the given item i in the given list.
743*486c6fdaSRichard Lowe  */
744*486c6fdaSRichard Lowe const char *
lt_stat_list_get_reason(void * ptr,int i)745*486c6fdaSRichard Lowe lt_stat_list_get_reason(void *ptr, int i)
746*486c6fdaSRichard Lowe {
747*486c6fdaSRichard Lowe 	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
748*486c6fdaSRichard Lowe 
749*486c6fdaSRichard Lowe 	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
750*486c6fdaSRichard Lowe 	    list->lt_sl_entries[i] == NULL) {
751*486c6fdaSRichard Lowe 		return (NULL);
752*486c6fdaSRichard Lowe 	}
753*486c6fdaSRichard Lowe 
754*486c6fdaSRichard Lowe 	g_assert(list->lt_sl_entries[i]->lt_se_string != NULL);
755*486c6fdaSRichard Lowe 
756*486c6fdaSRichard Lowe 	return (list->lt_sl_entries[i]->lt_se_string);
757*486c6fdaSRichard Lowe }
758*486c6fdaSRichard Lowe 
759*486c6fdaSRichard Lowe /*
760*486c6fdaSRichard Lowe  * Get maximum value of the given item i in the given list.
761*486c6fdaSRichard Lowe  */
762*486c6fdaSRichard Lowe uint64_t
lt_stat_list_get_max(void * ptr,int i)763*486c6fdaSRichard Lowe lt_stat_list_get_max(void *ptr, int i)
764*486c6fdaSRichard Lowe {
765*486c6fdaSRichard Lowe 	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
766*486c6fdaSRichard Lowe 
767*486c6fdaSRichard Lowe 	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
768*486c6fdaSRichard Lowe 	    list->lt_sl_entries[i] == NULL) {
769*486c6fdaSRichard Lowe 		return (0);
770*486c6fdaSRichard Lowe 	}
771*486c6fdaSRichard Lowe 
772*486c6fdaSRichard Lowe 	return (list->lt_sl_entries[i]->lt_se_data.lt_s_max);
773*486c6fdaSRichard Lowe }
774*486c6fdaSRichard Lowe 
775*486c6fdaSRichard Lowe /*
776*486c6fdaSRichard Lowe  * Get total value of the given item i in the given list.
777*486c6fdaSRichard Lowe  */
778*486c6fdaSRichard Lowe uint64_t
lt_stat_list_get_sum(void * ptr,int i)779*486c6fdaSRichard Lowe lt_stat_list_get_sum(void *ptr, int i)
780*486c6fdaSRichard Lowe {
781*486c6fdaSRichard Lowe 	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
782*486c6fdaSRichard Lowe 
783*486c6fdaSRichard Lowe 	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
784*486c6fdaSRichard Lowe 	    list->lt_sl_entries[i] == NULL) {
785*486c6fdaSRichard Lowe 		return (0);
786*486c6fdaSRichard Lowe 	}
787*486c6fdaSRichard Lowe 
788*486c6fdaSRichard Lowe 	return (list->lt_sl_entries[i]->lt_se_data.lt_s_total);
789*486c6fdaSRichard Lowe }
790*486c6fdaSRichard Lowe 
791*486c6fdaSRichard Lowe /*
792*486c6fdaSRichard Lowe  * Get count value of the given item i in the given list.
793*486c6fdaSRichard Lowe  */
794*486c6fdaSRichard Lowe uint64_t
lt_stat_list_get_count(void * ptr,int i)795*486c6fdaSRichard Lowe lt_stat_list_get_count(void *ptr, int i)
796*486c6fdaSRichard Lowe {
797*486c6fdaSRichard Lowe 	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
798*486c6fdaSRichard Lowe 
799*486c6fdaSRichard Lowe 	if (list == NULL || i < 0 || i >= list->lt_sl_entry_count ||
800*486c6fdaSRichard Lowe 	    list->lt_sl_entries[i] == NULL) {
801*486c6fdaSRichard Lowe 		return (0);
802*486c6fdaSRichard Lowe 	}
803*486c6fdaSRichard Lowe 
804*486c6fdaSRichard Lowe 	return (list->lt_sl_entries[i]->lt_se_data.lt_s_count);
805*486c6fdaSRichard Lowe }
806*486c6fdaSRichard Lowe 
807*486c6fdaSRichard Lowe /*
808*486c6fdaSRichard Lowe  * Get grand total of all latency in the list.
809*486c6fdaSRichard Lowe  */
810*486c6fdaSRichard Lowe uint64_t
lt_stat_list_get_gtotal(void * ptr)811*486c6fdaSRichard Lowe lt_stat_list_get_gtotal(void *ptr)
812*486c6fdaSRichard Lowe {
813*486c6fdaSRichard Lowe 	lt_stat_list_t *list = (lt_stat_list_t *)ptr;
814*486c6fdaSRichard Lowe 
815*486c6fdaSRichard Lowe 	if (list == NULL) {
816*486c6fdaSRichard Lowe 		return (0);
817*486c6fdaSRichard Lowe 	}
818*486c6fdaSRichard Lowe 
819*486c6fdaSRichard Lowe 	return (list->lt_sl_gtotal);
820*486c6fdaSRichard Lowe }
821*486c6fdaSRichard Lowe 
822*486c6fdaSRichard Lowe /*
823*486c6fdaSRichard Lowe  * ============================================================================
824*486c6fdaSRichard Lowe  * Process and thread list.
825*486c6fdaSRichard Lowe  * They share a lot of the static variables that are used for keeping
826*486c6fdaSRichard Lowe  * statistics, hence they are located in this file.
827*486c6fdaSRichard Lowe  */
828*486c6fdaSRichard Lowe 
829*486c6fdaSRichard Lowe /*
830*486c6fdaSRichard Lowe  * Helper function, sort by PID/TID ascend.
831*486c6fdaSRichard Lowe  */
832*486c6fdaSRichard Lowe static int
sort_id(lt_stat_collection_t * a,lt_stat_collection_t * b)833*486c6fdaSRichard Lowe sort_id(lt_stat_collection_t *a, lt_stat_collection_t *b)
834*486c6fdaSRichard Lowe {
835*486c6fdaSRichard Lowe 	return ((int)(a->lt_sc_id - b->lt_sc_id));
836*486c6fdaSRichard Lowe }
837*486c6fdaSRichard Lowe 
838*486c6fdaSRichard Lowe /*
839*486c6fdaSRichard Lowe  * Get the current list of processes. Call lt_stat_proc_list_free after use
840*486c6fdaSRichard Lowe  * to clean up.
841*486c6fdaSRichard Lowe  */
842*486c6fdaSRichard Lowe static int
plist_create(pid_t ** list)843*486c6fdaSRichard Lowe plist_create(pid_t ** list)
844*486c6fdaSRichard Lowe {
845*486c6fdaSRichard Lowe 	GList *pid_list, *walk;
846*486c6fdaSRichard Lowe 	int ret, count;
847*486c6fdaSRichard Lowe 
848*486c6fdaSRichard Lowe 	ret = g_hash_table_size(stat_system->lt_sc_children);
849*486c6fdaSRichard Lowe 	*list = (pid_t *)lt_malloc(sizeof (pid_t) * ret);
850*486c6fdaSRichard Lowe 
851*486c6fdaSRichard Lowe 	pid_list = g_hash_table_get_values(stat_system->lt_sc_children);
852*486c6fdaSRichard Lowe 	pid_list = g_list_sort(pid_list, (GCompareFunc)sort_id);
853*486c6fdaSRichard Lowe 
854*486c6fdaSRichard Lowe 	for (walk = pid_list, count = 0;
855*486c6fdaSRichard Lowe 	    walk != NULL && count < ret;
856*486c6fdaSRichard Lowe 	    walk = g_list_next(walk), ++count) {
857*486c6fdaSRichard Lowe 		(*list)[count] = (int)
858*486c6fdaSRichard Lowe 		    ((lt_stat_collection_t *)(walk->data))->lt_sc_id;
859*486c6fdaSRichard Lowe 	}
860*486c6fdaSRichard Lowe 
861*486c6fdaSRichard Lowe 	g_list_free(pid_list);
862*486c6fdaSRichard Lowe 
863*486c6fdaSRichard Lowe 	return (ret);
864*486c6fdaSRichard Lowe }
865*486c6fdaSRichard Lowe 
866*486c6fdaSRichard Lowe /*
867*486c6fdaSRichard Lowe  * Count the no. of threads currently present in a process.
868*486c6fdaSRichard Lowe  * Only thread that have SSLEEP are counted.
869*486c6fdaSRichard Lowe  */
870*486c6fdaSRichard Lowe /* ARGSUSED */
871*486c6fdaSRichard Lowe static void
count_threads(gpointer key,lt_stat_collection_t * stat_c,int * ret)872*486c6fdaSRichard Lowe count_threads(gpointer key, lt_stat_collection_t *stat_c, int *ret)
873*486c6fdaSRichard Lowe {
874*486c6fdaSRichard Lowe 	g_assert(ret != NULL);
875*486c6fdaSRichard Lowe 
876*486c6fdaSRichard Lowe 	if (stat_c->lt_sc_children != NULL) {
877*486c6fdaSRichard Lowe 		*ret += g_hash_table_size(stat_c->lt_sc_children);
878*486c6fdaSRichard Lowe 	}
879*486c6fdaSRichard Lowe }
880*486c6fdaSRichard Lowe 
881*486c6fdaSRichard Lowe /*
882*486c6fdaSRichard Lowe  * Get current list of processes and threads.
883*486c6fdaSRichard Lowe  * Call lt_stat_proc_list_free after use to clean up.
884*486c6fdaSRichard Lowe  */
885*486c6fdaSRichard Lowe static int
tlist_create(pid_t ** plist,id_t ** tlist)886*486c6fdaSRichard Lowe tlist_create(pid_t ** plist, id_t ** tlist)
887*486c6fdaSRichard Lowe {
888*486c6fdaSRichard Lowe 	GList *pid_list, *walk_p;
889*486c6fdaSRichard Lowe 	GList *tid_list, *walk_t;
890*486c6fdaSRichard Lowe 	int ret = 0;
891*486c6fdaSRichard Lowe 	int count = 0;
892*486c6fdaSRichard Lowe 
893*486c6fdaSRichard Lowe 	g_hash_table_foreach(stat_system->lt_sc_children,
894*486c6fdaSRichard Lowe 	    (GHFunc)count_threads, &ret);
895*486c6fdaSRichard Lowe 
896*486c6fdaSRichard Lowe 	*plist = (pid_t *)lt_malloc(sizeof (pid_t) * ret);
897*486c6fdaSRichard Lowe 	*tlist = (id_t *)lt_malloc(sizeof (id_t) * ret);
898*486c6fdaSRichard Lowe 
899*486c6fdaSRichard Lowe 	pid_list = g_hash_table_get_values(stat_system->lt_sc_children);
900*486c6fdaSRichard Lowe 	pid_list = g_list_sort(pid_list, (GCompareFunc)sort_id);
901*486c6fdaSRichard Lowe 
902*486c6fdaSRichard Lowe 	for (walk_p = pid_list; walk_p != NULL;
903*486c6fdaSRichard Lowe 	    walk_p = g_list_next(walk_p)) {
904*486c6fdaSRichard Lowe 		lt_stat_collection_t *stat_p =
905*486c6fdaSRichard Lowe 		    (lt_stat_collection_t *)walk_p->data;
906*486c6fdaSRichard Lowe 
907*486c6fdaSRichard Lowe 		if (stat_p->lt_sc_children == NULL) {
908*486c6fdaSRichard Lowe 			continue;
909*486c6fdaSRichard Lowe 		}
910*486c6fdaSRichard Lowe 
911*486c6fdaSRichard Lowe 		tid_list = g_hash_table_get_values(stat_p->lt_sc_children);
912*486c6fdaSRichard Lowe 		tid_list = g_list_sort(tid_list, (GCompareFunc)sort_id);
913*486c6fdaSRichard Lowe 
914*486c6fdaSRichard Lowe 		for (walk_t = tid_list; walk_t != NULL;
915*486c6fdaSRichard Lowe 		    walk_t = g_list_next(walk_t)) {
916*486c6fdaSRichard Lowe 			lt_stat_collection_t *stat_t =
917*486c6fdaSRichard Lowe 			    (lt_stat_collection_t *)walk_t->data;
918*486c6fdaSRichard Lowe 
919*486c6fdaSRichard Lowe 			(*plist)[count] = (int)stat_p->lt_sc_id;
920*486c6fdaSRichard Lowe 			(*tlist)[count] = (int)stat_t->lt_sc_id;
921*486c6fdaSRichard Lowe 
922*486c6fdaSRichard Lowe 			++count;
923*486c6fdaSRichard Lowe 		}
924*486c6fdaSRichard Lowe 		g_list_free(tid_list);
925*486c6fdaSRichard Lowe 	}
926*486c6fdaSRichard Lowe 
927*486c6fdaSRichard Lowe 	g_list_free(pid_list);
928*486c6fdaSRichard Lowe 	g_assert(count == ret);
929*486c6fdaSRichard Lowe 
930*486c6fdaSRichard Lowe 	return (ret);
931*486c6fdaSRichard Lowe }
932*486c6fdaSRichard Lowe 
933*486c6fdaSRichard Lowe /*
934*486c6fdaSRichard Lowe  * List of processes that are tracked by LatencyTOP.
935*486c6fdaSRichard Lowe  */
936*486c6fdaSRichard Lowe int
lt_stat_proc_list_create(pid_t ** plist,id_t ** tlist)937*486c6fdaSRichard Lowe lt_stat_proc_list_create(pid_t ** plist, id_t ** tlist)
938*486c6fdaSRichard Lowe {
939*486c6fdaSRichard Lowe 	if (plist == NULL) {
940*486c6fdaSRichard Lowe 		return (-1);
941*486c6fdaSRichard Lowe 	}
942*486c6fdaSRichard Lowe 
943*486c6fdaSRichard Lowe 	if (stat_system == NULL || stat_system->lt_sc_children == NULL) {
944*486c6fdaSRichard Lowe 		*plist = NULL;
945*486c6fdaSRichard Lowe 
946*486c6fdaSRichard Lowe 		if (tlist != NULL) {
947*486c6fdaSRichard Lowe 			*tlist = NULL;
948*486c6fdaSRichard Lowe 		}
949*486c6fdaSRichard Lowe 
950*486c6fdaSRichard Lowe 		return (0);
951*486c6fdaSRichard Lowe 	}
952*486c6fdaSRichard Lowe 
953*486c6fdaSRichard Lowe 	if (tlist == NULL) {
954*486c6fdaSRichard Lowe 		return (plist_create(plist));
955*486c6fdaSRichard Lowe 	} else {
956*486c6fdaSRichard Lowe 		return (tlist_create(plist, tlist));
957*486c6fdaSRichard Lowe 	}
958*486c6fdaSRichard Lowe }
959*486c6fdaSRichard Lowe 
960*486c6fdaSRichard Lowe /*
961*486c6fdaSRichard Lowe  * Free memory allocated by lt_stat_proc_list_create().
962*486c6fdaSRichard Lowe  */
963*486c6fdaSRichard Lowe void
lt_stat_proc_list_free(pid_t * plist,id_t * tlist)964*486c6fdaSRichard Lowe lt_stat_proc_list_free(pid_t *plist, id_t *tlist)
965*486c6fdaSRichard Lowe {
966*486c6fdaSRichard Lowe 	if (plist != NULL) {
967*486c6fdaSRichard Lowe 		free(plist);
968*486c6fdaSRichard Lowe 	}
969*486c6fdaSRichard Lowe 
970*486c6fdaSRichard Lowe 	if (tlist != NULL) {
971*486c6fdaSRichard Lowe 		free(tlist);
972*486c6fdaSRichard Lowe 	}
973*486c6fdaSRichard Lowe }
974*486c6fdaSRichard Lowe 
975*486c6fdaSRichard Lowe /*
976*486c6fdaSRichard Lowe  * Get executable name of the given process (ID).
977*486c6fdaSRichard Lowe  */
978*486c6fdaSRichard Lowe const char *
lt_stat_proc_get_name(pid_t pid)979*486c6fdaSRichard Lowe lt_stat_proc_get_name(pid_t pid)
980*486c6fdaSRichard Lowe {
981*486c6fdaSRichard Lowe 	lt_stat_collection_t *stat_p = NULL;
982*486c6fdaSRichard Lowe 
983*486c6fdaSRichard Lowe 	if (stat_system == NULL || stat_system->lt_sc_children == NULL) {
984*486c6fdaSRichard Lowe 		return (NULL);
985*486c6fdaSRichard Lowe 	}
986*486c6fdaSRichard Lowe 
987*486c6fdaSRichard Lowe 	stat_p = (lt_stat_collection_t *)g_hash_table_lookup(
988*486c6fdaSRichard Lowe 	    stat_system->lt_sc_children, LT_INT_TO_POINTER(pid));
989*486c6fdaSRichard Lowe 
990*486c6fdaSRichard Lowe 	if (stat_p != NULL) {
991*486c6fdaSRichard Lowe 		return (stat_p->lt_sc_name);
992*486c6fdaSRichard Lowe 	} else   {
993*486c6fdaSRichard Lowe 		return (NULL);
994*486c6fdaSRichard Lowe 	}
995*486c6fdaSRichard Lowe }
996*486c6fdaSRichard Lowe 
997*486c6fdaSRichard Lowe /*
998*486c6fdaSRichard Lowe  * Get number of threads.
999*486c6fdaSRichard Lowe  */
1000*486c6fdaSRichard Lowe int
lt_stat_proc_get_nthreads(pid_t pid)1001*486c6fdaSRichard Lowe lt_stat_proc_get_nthreads(pid_t pid)
1002*486c6fdaSRichard Lowe {
1003*486c6fdaSRichard Lowe 	lt_stat_collection_t *stat_p = NULL;
1004*486c6fdaSRichard Lowe 
1005*486c6fdaSRichard Lowe 	if (stat_system == NULL || stat_system->lt_sc_children == NULL) {
1006*486c6fdaSRichard Lowe 		return (0);
1007*486c6fdaSRichard Lowe 	}
1008*486c6fdaSRichard Lowe 
1009*486c6fdaSRichard Lowe 	stat_p = (lt_stat_collection_t *)g_hash_table_lookup(
1010*486c6fdaSRichard Lowe 	    stat_system->lt_sc_children, LT_INT_TO_POINTER(pid));
1011*486c6fdaSRichard Lowe 
1012*486c6fdaSRichard Lowe 	if (stat_p != NULL) {
1013*486c6fdaSRichard Lowe 		return (g_hash_table_size(stat_p->lt_sc_children));
1014*486c6fdaSRichard Lowe 	} else   {
1015*486c6fdaSRichard Lowe 		return (0);
1016*486c6fdaSRichard Lowe 	}
1017*486c6fdaSRichard Lowe }
1018*486c6fdaSRichard Lowe 
1019*486c6fdaSRichard Lowe /*
1020*486c6fdaSRichard Lowe  * Update statistics for synchronization objects.
1021*486c6fdaSRichard Lowe  */
1022*486c6fdaSRichard Lowe void
lt_stat_update_sobj(pid_t pid,id_t tid,int stype,unsigned long long wchan,lt_stat_type_t type,uint64_t value)1023*486c6fdaSRichard Lowe lt_stat_update_sobj(pid_t pid, id_t tid, int stype,
1024*486c6fdaSRichard Lowe     unsigned long long wchan,
1025*486c6fdaSRichard Lowe     lt_stat_type_t type, uint64_t value)
1026*486c6fdaSRichard Lowe {
1027*486c6fdaSRichard Lowe 	lt_sobj_id_t id;
1028*486c6fdaSRichard Lowe 	lt_sobj_t *sobj;
1029*486c6fdaSRichard Lowe 	int cause_id;
1030*486c6fdaSRichard Lowe 	lt_stat_collection_t *stat_t = NULL;
1031*486c6fdaSRichard Lowe 
1032*486c6fdaSRichard Lowe 	stat_t = get_stat_c(pid, tid);
1033*486c6fdaSRichard Lowe 
1034*486c6fdaSRichard Lowe 	if (stat_t == NULL) {
1035*486c6fdaSRichard Lowe 		return;
1036*486c6fdaSRichard Lowe 	}
1037*486c6fdaSRichard Lowe 
1038*486c6fdaSRichard Lowe 	id.lt_soi_type = stype;
1039*486c6fdaSRichard Lowe 	id.lt_soi_addr = wchan;
1040*486c6fdaSRichard Lowe 	sobj = lookup_sobj(&id);
1041*486c6fdaSRichard Lowe 
1042*486c6fdaSRichard Lowe 	if (sobj == NULL) {
1043*486c6fdaSRichard Lowe 		return;
1044*486c6fdaSRichard Lowe 	}
1045*486c6fdaSRichard Lowe 
1046*486c6fdaSRichard Lowe 	cause_id = sobj->lt_so_cause_id;
1047*486c6fdaSRichard Lowe 
1048*486c6fdaSRichard Lowe 	update_stat_entry(stat_t, cause_id, type, value,
1049*486c6fdaSRichard Lowe 	    sobj->lt_so_string, GROUP_SOBJ);
1050*486c6fdaSRichard Lowe }
1051