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