1 /* Sysprof -- Sampling, systemwide CPU profiler
2 * Copyright 2004, Red Hat, Inc.
3 * Copyright 2004, 2005, Soeren Sandmann
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 #include "stackstash.h"
26 GHashTable
* nodes_by_data
;
27 GDestroyNotify destroy
;
29 StackNode
* cached_nodes
;
34 stack_node_new (StackStash
*stash
)
38 if (!stash
->cached_nodes
)
40 #define BLOCK_SIZE 32768
41 #define N_NODES (BLOCK_SIZE / sizeof (StackNode))
43 StackNode
*block
= g_malloc (BLOCK_SIZE
);
46 for (i
= 0; i
< N_NODES
; ++i
)
48 block
[i
].next
= stash
->cached_nodes
;
49 stash
->cached_nodes
= &(block
[i
]);
52 g_ptr_array_add (stash
->blocks
, block
);
55 node
= stash
->cached_nodes
;
56 stash
->cached_nodes
= node
->next
;
58 node
->siblings
= NULL
;
59 node
->children
= NULL
;
69 /* "destroy", if non-NULL, is called once on every address */
71 create_stack_stash (GDestroyNotify destroy
)
73 StackStash
*stash
= g_new (StackStash
, 1);
76 stash
->nodes_by_data
= g_hash_table_new (g_direct_hash
, g_direct_equal
);
78 stash
->destroy
= destroy
;
80 stash
->cached_nodes
= NULL
;
81 stash
->blocks
= g_ptr_array_new ();
88 stack_stash_new (GDestroyNotify destroy
)
90 return create_stack_stash (destroy
);
95 free_key (gpointer key
,
99 GDestroyNotify destroy
= data
;
105 stack_stash_free (StackStash
*stash
)
111 g_hash_table_foreach (stash
->nodes_by_data
, free_key
,
115 g_hash_table_destroy (stash
->nodes_by_data
);
117 for (i
= 0; i
< stash
->blocks
->len
; ++i
)
118 g_free (stash
->blocks
->pdata
[i
]);
120 g_ptr_array_free (stash
->blocks
, TRUE
);
126 decorate_node (StackStash
*stash
,
130 gboolean toplevel
= TRUE
;
132 /* FIXME: we will probably want to do this lazily,
133 * and more efficiently (only walk the tree once).
135 for (n
= node
->parent
; n
!= NULL
; n
= n
->parent
)
137 if (n
->address
== node
->address
)
144 node
->toplevel
= toplevel
;
146 node
->next
= g_hash_table_lookup (
147 stash
->nodes_by_data
, node
->address
);
148 g_hash_table_insert (
149 stash
->nodes_by_data
, node
->address
, node
);
153 stack_stash_add_trace (StackStash
*stash
,
158 StackNode
**location
= &(stash
->root
);
159 StackNode
*parent
= NULL
;
165 for (i
= n_addrs
- 1; i
>= 0; --i
)
167 StackNode
*match
= NULL
;
170 for (n
= *location
; n
!= NULL
; n
= n
->siblings
)
172 if (n
->address
== (gpointer
)addrs
[i
])
181 match
= stack_node_new (stash
);
182 match
->address
= (gpointer
)addrs
[i
];
183 match
->siblings
= *location
;
184 match
->parent
= parent
;
187 decorate_node (stash
, match
);
190 match
->total
+= size
;
192 location
= &(match
->children
);
196 parent
->size
+= size
;
202 do_callback (StackNode
*node
,
217 link
.data
= node
->address
;
220 func (&link
, node
->size
, data
);
222 do_callback (node
->children
, &link
, func
, data
);
224 node
= node
->siblings
;
232 stack_stash_foreach (StackStash
*stash
,
233 StackFunction stack_func
,
236 do_callback (stash
->root
, NULL
, stack_func
, data
);
240 stack_node_foreach_trace (StackNode
*node
,
247 link
.data
= node
->address
;
251 func (&link
, node
->size
, data
);
253 do_callback (node
->children
, &link
, func
, data
);
257 stack_stash_unref (StackStash
*stash
)
260 if (stash
->ref_count
== 0)
261 stack_stash_free (stash
);
265 stack_stash_ref (StackStash
*stash
)
272 stack_stash_find_node (StackStash
*stash
,
275 g_return_val_if_fail (stash
!= NULL
, NULL
);
277 return g_hash_table_lookup (stash
->nodes_by_data
, data
);
287 do_foreach (gpointer key
, gpointer value
, gpointer data
)
291 info
->func (value
, info
->data
);
295 stack_stash_foreach_by_address (StackStash
*stash
,
303 g_hash_table_foreach (stash
->nodes_by_data
, do_foreach
, &info
);
307 stack_stash_get_root (StackStash
*stash
)
313 build_hash_table (StackNode
*node
,
319 build_hash_table (node
->siblings
, stash
);
320 build_hash_table (node
->children
, stash
);
322 node
->next
= g_hash_table_lookup (
323 stash
->nodes_by_data
, node
->address
);
324 g_hash_table_insert (
325 stash
->nodes_by_data
, node
->address
, node
);
329 stack_stash_set_root (StackStash
*stash
,
332 g_return_if_fail (stash
->root
== NULL
);
333 g_return_if_fail (g_hash_table_size (stash
->nodes_by_data
) == 0);
336 build_hash_table (stash
->root
, stash
);