pmcpl_calltree.c revision 233611
1203790Sfabient/*-
2233611Sfabient * Copyright (c) 2012, Fabien Thomas
3203790Sfabient * All rights reserved.
4203790Sfabient *
5203790Sfabient * Redistribution and use in source and binary forms, with or without
6203790Sfabient * modification, are permitted provided that the following conditions
7203790Sfabient * are met:
8203790Sfabient * 1. Redistributions of source code must retain the above copyright
9203790Sfabient *    notice, this list of conditions and the following disclaimer.
10203790Sfabient * 2. Redistributions in binary form must reproduce the above copyright
11203790Sfabient *    notice, this list of conditions and the following disclaimer in the
12203790Sfabient *    documentation and/or other materials provided with the distribution.
13203790Sfabient *
14203790Sfabient * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15203790Sfabient * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16203790Sfabient * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17203790Sfabient * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18203790Sfabient * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19203790Sfabient * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20203790Sfabient * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21203790Sfabient * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22203790Sfabient * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23203790Sfabient * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24203790Sfabient * SUCH DAMAGE.
25203790Sfabient */
26203790Sfabient
27203790Sfabient/*
28203790Sfabient * Process hwpmc(4) samples as calltree.
29203790Sfabient *
30203790Sfabient * Output file format compatible with Kcachegrind (kdesdk).
31203790Sfabient * Handle top mode with a sorted tree display.
32203790Sfabient */
33203790Sfabient
34203790Sfabient#include <sys/cdefs.h>
35203790Sfabient__FBSDID("$FreeBSD: head/usr.sbin/pmcstat/pmcpl_calltree.c 233611 2012-03-28 16:23:40Z fabient $");
36203790Sfabient
37203790Sfabient#include <sys/param.h>
38203790Sfabient#include <sys/endian.h>
39203790Sfabient#include <sys/queue.h>
40203790Sfabient
41203790Sfabient#include <assert.h>
42203790Sfabient#include <curses.h>
43203790Sfabient#include <ctype.h>
44203790Sfabient#include <err.h>
45203790Sfabient#include <errno.h>
46203790Sfabient#include <fcntl.h>
47203790Sfabient#include <pmc.h>
48203790Sfabient#include <pmclog.h>
49203790Sfabient#include <stdint.h>
50203790Sfabient#include <stdio.h>
51203790Sfabient#include <stdlib.h>
52203790Sfabient#include <string.h>
53203790Sfabient#include <unistd.h>
54203790Sfabient#include <sysexits.h>
55203790Sfabient
56203790Sfabient#include "pmcstat.h"
57203790Sfabient#include "pmcstat_log.h"
58203790Sfabient#include "pmcstat_top.h"
59203790Sfabient#include "pmcpl_calltree.h"
60203790Sfabient
61233611Sfabient#define	PMCPL_CT_GROWSIZE	4
62203790Sfabient
63203790Sfabientstatic int pmcstat_skiplink = 0;
64203790Sfabient
65203790Sfabientstruct pmcpl_ct_node;
66203790Sfabient
67203790Sfabient/* Get the sample value for PMC a. */
68233611Sfabient#define	PMCPL_CT_SAMPLE(a, b) \
69203790Sfabient	((a) < (b)->npmcs ? (b)->sb[a] : 0)
70203790Sfabient
71203790Sfabient/* Get the sample value in percent related to rsamples. */
72233611Sfabient#define	PMCPL_CT_SAMPLEP(a, b) \
73203790Sfabient	(PMCPL_CT_SAMPLE(a, b) * 100.0 / rsamples->sb[a])
74203790Sfabient
75203790Sfabientstruct pmcpl_ct_sample {
76203790Sfabient	int		npmcs;		/* Max pmc index available. */
77203790Sfabient	unsigned	*sb;		/* Sample buffer for 0..npmcs. */
78203790Sfabient};
79203790Sfabient
80203790Sfabientstruct pmcpl_ct_arc {
81203790Sfabient	struct pmcpl_ct_sample	pcta_samples;
82203790Sfabient	struct pmcpl_ct_sample	pcta_callid;
83203790Sfabient	unsigned		pcta_call;
84203790Sfabient	struct pmcpl_ct_node	*pcta_child;
85203790Sfabient};
86203790Sfabient
87203790Sfabientstruct pmcpl_ct_instr {
88203790Sfabient	uintfptr_t		pctf_func;
89203790Sfabient	struct pmcpl_ct_sample	pctf_samples;
90203790Sfabient};
91203790Sfabient
92203790Sfabient/*
93203790Sfabient * Each calltree node is tracked by a pmcpl_ct_node struct.
94203790Sfabient */
95203790Sfabientstruct pmcpl_ct_node {
96203790Sfabient	struct pmcstat_image	*pct_image;
97203790Sfabient	uintfptr_t		pct_func;
98233611Sfabient
99233611Sfabient	struct pmcstat_symbol	*pct_sym;
100233611Sfabient	pmcstat_interned_string	pct_ifl;
101233611Sfabient	pmcstat_interned_string	pct_ifn;
102233611Sfabient
103203790Sfabient	struct pmcpl_ct_sample	pct_samples;
104203790Sfabient
105203790Sfabient	int			pct_narc;
106203790Sfabient	int			pct_arc_c;
107203790Sfabient	struct pmcpl_ct_arc 	*pct_arc;
108203790Sfabient
109203790Sfabient	/* TODO: optimize for large number of items. */
110203790Sfabient	int			pct_ninstr;
111203790Sfabient	int			pct_instr_c;
112203790Sfabient	struct pmcpl_ct_instr	*pct_instr;
113233611Sfabient
114233611Sfabient#define PMCPL_PCT_ADDR	0
115233611Sfabient#define PMCPL_PCT_NAME	1
116233611Sfabient	char			pct_type;
117233611Sfabient#define	PMCPL_PCT_WHITE	0
118233611Sfabient#define	PMCPL_PCT_GREY	1
119233611Sfabient#define	PMCPL_PCT_BLACK	2
120233611Sfabient	char			pct_color;
121203790Sfabient};
122203790Sfabient
123203790Sfabientstruct pmcpl_ct_node_hash {
124203790Sfabient	struct pmcpl_ct_node  *pch_ctnode;
125233611Sfabient	STAILQ_ENTRY(pmcpl_ct_node_hash) pch_next;
126203790Sfabient};
127203790Sfabient
128203790Sfabientstruct pmcpl_ct_sample pmcpl_ct_callid;
129203790Sfabient
130233611Sfabient#define	PMCPL_CT_MAXCOL		PMC_CALLCHAIN_DEPTH_MAX
131233611Sfabient#define	PMCPL_CT_MAXLINE	1024	/* TODO: dynamic. */
132203790Sfabient
133207755Sfabientstruct pmcpl_ct_line {
134207755Sfabient	unsigned	ln_sum;
135207755Sfabient	unsigned	ln_index;
136207755Sfabient};
137207755Sfabient
138207755Sfabientstruct pmcpl_ct_line	pmcpl_ct_topmax[PMCPL_CT_MAXLINE+1];
139233611Sfabientstruct pmcpl_ct_node
140233611Sfabient    *pmcpl_ct_topscreen[PMCPL_CT_MAXCOL+1][PMCPL_CT_MAXLINE+1];
141207755Sfabient
142203790Sfabient/*
143203790Sfabient * All nodes indexed by function/image name are placed in a hash table.
144203790Sfabient */
145233611Sfabientstatic STAILQ_HEAD(,pmcpl_ct_node_hash) pmcpl_ct_node_hash[PMCSTAT_NHASH];
146203790Sfabient
147203790Sfabient/*
148203790Sfabient * Root node for the graph.
149203790Sfabient */
150203790Sfabientstatic struct pmcpl_ct_node *pmcpl_ct_root;
151203790Sfabient
152203790Sfabient/*
153203790Sfabient * Prototypes
154203790Sfabient */
155203790Sfabient
156203790Sfabient/*
157203790Sfabient * Initialize a samples.
158203790Sfabient */
159203790Sfabient
160203790Sfabientstatic void
161203790Sfabientpmcpl_ct_samples_init(struct pmcpl_ct_sample *samples)
162203790Sfabient{
163203790Sfabient
164203790Sfabient	samples->npmcs = 0;
165203790Sfabient	samples->sb = NULL;
166203790Sfabient}
167203790Sfabient
168203790Sfabient/*
169203790Sfabient * Free a samples.
170203790Sfabient */
171203790Sfabient
172203790Sfabientstatic void
173203790Sfabientpmcpl_ct_samples_free(struct pmcpl_ct_sample *samples)
174203790Sfabient{
175203790Sfabient
176203790Sfabient	samples->npmcs = 0;
177203790Sfabient	free(samples->sb);
178203790Sfabient	samples->sb = NULL;
179203790Sfabient}
180203790Sfabient
181203790Sfabient/*
182203790Sfabient * Grow a sample block to store pmcstat_npmcs PMCs.
183203790Sfabient */
184203790Sfabient
185203790Sfabientstatic void
186203790Sfabientpmcpl_ct_samples_grow(struct pmcpl_ct_sample *samples)
187203790Sfabient{
188203790Sfabient	int npmcs;
189203790Sfabient
190203790Sfabient	/* Enough storage. */
191203790Sfabient	if (pmcstat_npmcs <= samples->npmcs)
192203790Sfabient                return;
193203790Sfabient
194203790Sfabient	npmcs = samples->npmcs +
195203790Sfabient	    max(pmcstat_npmcs - samples->npmcs, PMCPL_CT_GROWSIZE);
196203790Sfabient	samples->sb = realloc(samples->sb, npmcs * sizeof(unsigned));
197203790Sfabient	if (samples->sb == NULL)
198203790Sfabient		errx(EX_SOFTWARE, "ERROR: out of memory");
199203790Sfabient	bzero((char *)samples->sb + samples->npmcs * sizeof(unsigned),
200203790Sfabient	    (npmcs - samples->npmcs) * sizeof(unsigned));
201203790Sfabient	samples->npmcs = npmcs;
202203790Sfabient}
203203790Sfabient
204203790Sfabient/*
205203790Sfabient * Compute the sum of all root arcs.
206203790Sfabient */
207203790Sfabient
208203790Sfabientstatic void
209203790Sfabientpmcpl_ct_samples_root(struct pmcpl_ct_sample *samples)
210203790Sfabient{
211203790Sfabient	int i, pmcin;
212203790Sfabient
213203790Sfabient	pmcpl_ct_samples_init(samples);
214203790Sfabient	pmcpl_ct_samples_grow(samples);
215203790Sfabient
216203790Sfabient	for (i = 0; i < pmcpl_ct_root->pct_narc; i++)
217203790Sfabient		for (pmcin = 0; pmcin < pmcstat_npmcs; pmcin++)
218203790Sfabient			samples->sb[pmcin] += PMCPL_CT_SAMPLE(pmcin,
219203790Sfabient			    &pmcpl_ct_root->pct_arc[i].pcta_samples);
220203790Sfabient}
221203790Sfabient
222203790Sfabient/*
223203790Sfabient * Grow the arc table.
224203790Sfabient */
225203790Sfabient
226203790Sfabientstatic void
227203790Sfabientpmcpl_ct_arc_grow(int cursize, int *maxsize, struct pmcpl_ct_arc **items)
228203790Sfabient{
229203790Sfabient	int nmaxsize;
230203790Sfabient
231203790Sfabient	if (cursize < *maxsize)
232203790Sfabient		return;
233203790Sfabient
234203790Sfabient	nmaxsize = *maxsize + max(cursize + 1 - *maxsize, PMCPL_CT_GROWSIZE);
235203790Sfabient	*items = realloc(*items, nmaxsize * sizeof(struct pmcpl_ct_arc));
236203790Sfabient	if (*items == NULL)
237203790Sfabient		errx(EX_SOFTWARE, "ERROR: out of memory");
238203790Sfabient	bzero((char *)*items + *maxsize * sizeof(struct pmcpl_ct_arc),
239203790Sfabient	    (nmaxsize - *maxsize) * sizeof(struct pmcpl_ct_arc));
240203790Sfabient	*maxsize = nmaxsize;
241203790Sfabient}
242203790Sfabient
243203790Sfabient/*
244203790Sfabient * Grow the instr table.
245203790Sfabient */
246203790Sfabient
247203790Sfabientstatic void
248203790Sfabientpmcpl_ct_instr_grow(int cursize, int *maxsize, struct pmcpl_ct_instr **items)
249203790Sfabient{
250203790Sfabient	int nmaxsize;
251203790Sfabient
252203790Sfabient	if (cursize < *maxsize)
253203790Sfabient		return;
254203790Sfabient
255203790Sfabient	nmaxsize = *maxsize + max(cursize + 1 - *maxsize, PMCPL_CT_GROWSIZE);
256203790Sfabient	*items = realloc(*items, nmaxsize * sizeof(struct pmcpl_ct_instr));
257203790Sfabient	if (*items == NULL)
258203790Sfabient		errx(EX_SOFTWARE, "ERROR: out of memory");
259203790Sfabient	bzero((char *)*items + *maxsize * sizeof(struct pmcpl_ct_instr),
260203790Sfabient	    (nmaxsize - *maxsize) * sizeof(struct pmcpl_ct_instr));
261203790Sfabient	*maxsize = nmaxsize;
262203790Sfabient}
263203790Sfabient
264203790Sfabient/*
265203790Sfabient * Add a new instruction sample to given node.
266203790Sfabient */
267203790Sfabient
268203790Sfabientstatic void
269233611Sfabientpmcpl_ct_instr_add(struct pmcpl_ct_node *ct, int pmcin,
270233611Sfabient    uintfptr_t pc, unsigned v)
271203790Sfabient{
272203790Sfabient	int i;
273203790Sfabient	struct pmcpl_ct_instr *in;
274203790Sfabient
275203790Sfabient	for (i = 0; i<ct->pct_ninstr; i++) {
276203790Sfabient		if (ct->pct_instr[i].pctf_func == pc) {
277203790Sfabient			in = &ct->pct_instr[i];
278203790Sfabient			pmcpl_ct_samples_grow(&in->pctf_samples);
279233611Sfabient			in->pctf_samples.sb[pmcin] += v;
280203790Sfabient			return;
281203790Sfabient		}
282203790Sfabient	}
283203790Sfabient
284203790Sfabient	pmcpl_ct_instr_grow(ct->pct_ninstr, &ct->pct_instr_c, &ct->pct_instr);
285203790Sfabient	in = &ct->pct_instr[ct->pct_ninstr];
286203790Sfabient	in->pctf_func = pc;
287203790Sfabient	pmcpl_ct_samples_init(&in->pctf_samples);
288203790Sfabient	pmcpl_ct_samples_grow(&in->pctf_samples);
289233611Sfabient	in->pctf_samples.sb[pmcin] = v;
290203790Sfabient	ct->pct_ninstr++;
291203790Sfabient}
292203790Sfabient
293203790Sfabient/*
294203790Sfabient * Allocate a new node.
295203790Sfabient */
296203790Sfabient
297203790Sfabientstatic struct pmcpl_ct_node *
298233611Sfabientpmcpl_ct_node_allocate(void)
299203790Sfabient{
300203790Sfabient	struct pmcpl_ct_node *ct;
301203790Sfabient
302203790Sfabient	if ((ct = malloc(sizeof(*ct))) == NULL)
303203790Sfabient		err(EX_OSERR, "ERROR: Cannot allocate callgraph node");
304203790Sfabient
305203790Sfabient	pmcpl_ct_samples_init(&ct->pct_samples);
306203790Sfabient
307233611Sfabient	ct->pct_sym	= NULL;
308233611Sfabient	ct->pct_image	= NULL;
309233611Sfabient	ct->pct_func	= 0;
310233611Sfabient
311203790Sfabient	ct->pct_narc	= 0;
312203790Sfabient	ct->pct_arc_c	= 0;
313203790Sfabient	ct->pct_arc	= NULL;
314203790Sfabient
315203790Sfabient	ct->pct_ninstr	= 0;
316203790Sfabient	ct->pct_instr_c	= 0;
317203790Sfabient	ct->pct_instr	= NULL;
318203790Sfabient
319233611Sfabient	ct->pct_color   = PMCPL_PCT_WHITE;
320233611Sfabient
321203790Sfabient	return (ct);
322203790Sfabient}
323203790Sfabient
324203790Sfabient/*
325203790Sfabient * Free a node.
326203790Sfabient */
327203790Sfabient
328203790Sfabientstatic void
329203790Sfabientpmcpl_ct_node_free(struct pmcpl_ct_node *ct)
330203790Sfabient{
331203790Sfabient	int i;
332203790Sfabient
333203790Sfabient	for (i = 0; i < ct->pct_narc; i++) {
334203790Sfabient		pmcpl_ct_samples_free(&ct->pct_arc[i].pcta_samples);
335203790Sfabient		pmcpl_ct_samples_free(&ct->pct_arc[i].pcta_callid);
336203790Sfabient	}
337203790Sfabient
338203790Sfabient	pmcpl_ct_samples_free(&ct->pct_samples);
339203790Sfabient	free(ct->pct_arc);
340203790Sfabient	free(ct->pct_instr);
341203790Sfabient	free(ct);
342203790Sfabient}
343203790Sfabient
344203790Sfabient/*
345203790Sfabient * Clear the graph tag on each node.
346203790Sfabient */
347203790Sfabientstatic void
348203790Sfabientpmcpl_ct_node_cleartag(void)
349203790Sfabient{
350203790Sfabient	int i;
351203790Sfabient	struct pmcpl_ct_node_hash *pch;
352203790Sfabient
353203790Sfabient	for (i = 0; i < PMCSTAT_NHASH; i++)
354233611Sfabient		STAILQ_FOREACH(pch, &pmcpl_ct_node_hash[i], pch_next)
355233611Sfabient			pch->pch_ctnode->pct_color = PMCPL_PCT_WHITE;
356203790Sfabient
357233611Sfabient	pmcpl_ct_root->pct_color = PMCPL_PCT_WHITE;
358203790Sfabient}
359203790Sfabient
360203790Sfabient/*
361203790Sfabient * Print the callchain line by line with maximum cost at top.
362203790Sfabient */
363203790Sfabient
364203790Sfabientstatic int
365203790Sfabientpmcpl_ct_node_dumptop(int pmcin, struct pmcpl_ct_node *ct,
366207755Sfabient    struct pmcpl_ct_sample *rsamples, int x, int *y)
367203790Sfabient{
368207755Sfabient	int i, terminal;
369210766Sfabient	struct pmcpl_ct_arc *arc;
370203790Sfabient
371233611Sfabient	if (ct->pct_color == PMCPL_PCT_GREY)
372203790Sfabient		return 0;
373203790Sfabient
374203790Sfabient	if (x >= PMCPL_CT_MAXCOL) {
375203790Sfabient		pmcpl_ct_topscreen[x][*y] = NULL;
376203790Sfabient		return 1;
377203790Sfabient	}
378203790Sfabient	pmcpl_ct_topscreen[x][*y] = ct;
379203790Sfabient
380203790Sfabient	/*
381207755Sfabient	 * Check if this is a terminal node.
382207755Sfabient	 * We need to check that some samples exist
383207755Sfabient	 * for at least one arc for that PMC.
384203790Sfabient	 */
385207755Sfabient	terminal = 1;
386210766Sfabient	for (i = 0; i < ct->pct_narc; i++) {
387210766Sfabient		arc = &ct->pct_arc[i];
388233611Sfabient		if (arc->pcta_child->pct_color != PMCPL_PCT_GREY &&
389233611Sfabient		    PMCPL_CT_SAMPLE(pmcin,
390210766Sfabient		    &arc->pcta_samples) != 0 &&
391210766Sfabient		    PMCPL_CT_SAMPLEP(pmcin,
392233611Sfabient		    &arc->pcta_samples) > pmcstat_threshold) {
393207755Sfabient			terminal = 0;
394207755Sfabient			break;
395207755Sfabient		}
396210766Sfabient	}
397207755Sfabient
398207755Sfabient	if (ct->pct_narc == 0 || terminal) {
399203790Sfabient		pmcpl_ct_topscreen[x+1][*y] = NULL;
400207755Sfabient		if (*y >= PMCPL_CT_MAXLINE)
401203790Sfabient			return 1;
402203790Sfabient		*y = *y + 1;
403203790Sfabient		for (i=0; i < x; i++)
404203790Sfabient			pmcpl_ct_topscreen[i][*y] =
405203790Sfabient			    pmcpl_ct_topscreen[i][*y - 1];
406203790Sfabient		return 0;
407203790Sfabient	}
408203790Sfabient
409233611Sfabient	ct->pct_color = PMCPL_PCT_GREY;
410203790Sfabient	for (i = 0; i < ct->pct_narc; i++) {
411206090Sfabient		if (PMCPL_CT_SAMPLE(pmcin,
412206090Sfabient		    &ct->pct_arc[i].pcta_samples) == 0)
413206090Sfabient			continue;
414203790Sfabient		if (PMCPL_CT_SAMPLEP(pmcin,
415203790Sfabient		    &ct->pct_arc[i].pcta_samples) > pmcstat_threshold) {
416203790Sfabient			if (pmcpl_ct_node_dumptop(pmcin,
417203790Sfabient			        ct->pct_arc[i].pcta_child,
418233611Sfabient			        rsamples, x+1, y)) {
419233611Sfabient				ct->pct_color = PMCPL_PCT_BLACK;
420203790Sfabient				return 1;
421233611Sfabient			}
422203790Sfabient		}
423203790Sfabient	}
424233611Sfabient	ct->pct_color = PMCPL_PCT_BLACK;
425203790Sfabient
426203790Sfabient	return 0;
427203790Sfabient}
428203790Sfabient
429203790Sfabient/*
430207755Sfabient * Compare two top line by sum.
431207755Sfabient */
432207755Sfabientstatic int
433207755Sfabientpmcpl_ct_line_compare(const void *a, const void *b)
434207755Sfabient{
435207755Sfabient	const struct pmcpl_ct_line *ct1, *ct2;
436207755Sfabient
437207755Sfabient	ct1 = (const struct pmcpl_ct_line *) a;
438207755Sfabient	ct2 = (const struct pmcpl_ct_line *) b;
439207755Sfabient
440207755Sfabient	/* Sort in reverse order */
441207755Sfabient	if (ct1->ln_sum < ct2->ln_sum)
442207755Sfabient		return (1);
443207755Sfabient	if (ct1->ln_sum > ct2->ln_sum)
444207755Sfabient		return (-1);
445207755Sfabient	return (0);
446207755Sfabient}
447207755Sfabient
448207755Sfabient/*
449203790Sfabient * Format and display given PMC index.
450203790Sfabient */
451203790Sfabient
452203790Sfabientstatic void
453203790Sfabientpmcpl_ct_node_printtop(struct pmcpl_ct_sample *rsamples, int pmcin, int maxy)
454203790Sfabient{
455207755Sfabient#undef	TS
456207755Sfabient#undef	TSI
457207755Sfabient#define	TS(x, y)	(pmcpl_ct_topscreen[x][y])
458207755Sfabient#define	TSI(x, y)	(pmcpl_ct_topscreen[x][pmcpl_ct_topmax[y].ln_index])
459207755Sfabient
460203790Sfabient	int v_attrs, ns_len, vs_len, is_len, width, indentwidth, x, y;
461203790Sfabient	float v;
462203790Sfabient	char ns[30], vs[10], is[20];
463203790Sfabient	struct pmcpl_ct_node *ct;
464203790Sfabient	const char *space = " ";
465203790Sfabient
466207755Sfabient	/*
467207755Sfabient	 * Sort by line cost.
468207755Sfabient	 */
469207755Sfabient	for (y = 0; ; y++) {
470207755Sfabient		ct = TS(1, y);
471207755Sfabient		if (ct == NULL)
472207755Sfabient			break;
473207755Sfabient
474207755Sfabient		pmcpl_ct_topmax[y].ln_sum = 0;
475207755Sfabient		pmcpl_ct_topmax[y].ln_index = y;
476207755Sfabient		for (x = 1; TS(x, y) != NULL; x++) {
477207755Sfabient			pmcpl_ct_topmax[y].ln_sum +=
478207755Sfabient			    PMCPL_CT_SAMPLE(pmcin, &TS(x, y)->pct_samples);
479207755Sfabient		}
480207755Sfabient	}
481207755Sfabient	qsort(pmcpl_ct_topmax, y, sizeof(pmcpl_ct_topmax[0]),
482207755Sfabient	    pmcpl_ct_line_compare);
483207755Sfabient	pmcpl_ct_topmax[y].ln_index = y;
484207755Sfabient
485203790Sfabient	for (y = 0; y < maxy; y++) {
486207755Sfabient		ct = TSI(1, y);
487207755Sfabient		if (ct == NULL)
488207755Sfabient			break;
489203790Sfabient
490207755Sfabient		if (y > 0)
491207755Sfabient			PMCSTAT_PRINTW("\n");
492203790Sfabient
493207755Sfabient		/* Output sum. */
494207755Sfabient		v = pmcpl_ct_topmax[y].ln_sum * 100.0 /
495207755Sfabient		    rsamples->sb[pmcin];
496207755Sfabient		snprintf(vs, sizeof(vs), "%.1f", v);
497207755Sfabient		v_attrs = PMCSTAT_ATTRPERCENT(v);
498207755Sfabient		PMCSTAT_ATTRON(v_attrs);
499207755Sfabient		PMCSTAT_PRINTW("%5.5s ", vs);
500207755Sfabient		PMCSTAT_ATTROFF(v_attrs);
501203790Sfabient
502207755Sfabient		width = indentwidth = 5 + 1;
503207755Sfabient
504207755Sfabient		for (x = 1; (ct = TSI(x, y)) != NULL; x++) {
505207755Sfabient
506203790Sfabient			vs[0] = '\0'; vs_len = 0;
507203790Sfabient			is[0] = '\0'; is_len = 0;
508203790Sfabient
509203790Sfabient			/* Format value. */
510203790Sfabient			v = PMCPL_CT_SAMPLEP(pmcin, &ct->pct_samples);
511203790Sfabient			if (v > pmcstat_threshold)
512207755Sfabient				vs_len  = snprintf(vs, sizeof(vs),
513207755Sfabient				    "(%.1f%%)", v);
514203790Sfabient			v_attrs = PMCSTAT_ATTRPERCENT(v);
515203790Sfabient
516203790Sfabient			if (pmcstat_skiplink && v <= pmcstat_threshold) {
517207755Sfabient				strlcpy(ns, ".", sizeof(ns));
518207755Sfabient				ns_len = 1;
519207755Sfabient			} else {
520233611Sfabient			if (ct->pct_sym != NULL) {
521203790Sfabient				ns_len = snprintf(ns, sizeof(ns), "%s",
522233611Sfabient				    pmcstat_string_unintern(ct->pct_sym->ps_name));
523203790Sfabient			} else
524203790Sfabient				ns_len = snprintf(ns, sizeof(ns), "%p",
525203790Sfabient				    (void *)ct->pct_func);
526203790Sfabient
527203790Sfabient			/* Format image. */
528207755Sfabient			if (x == 1 ||
529207755Sfabient			    TSI(x-1, y)->pct_image != ct->pct_image)
530203790Sfabient				is_len = snprintf(is, sizeof(is), "@%s",
531203790Sfabient				    pmcstat_string_unintern(ct->pct_image->pi_name));
532203790Sfabient
533203790Sfabient			/* Check for line wrap. */
534203790Sfabient			width += ns_len + is_len + vs_len + 1;
535207755Sfabient			}
536203790Sfabient			if (width >= pmcstat_displaywidth) {
537205693Sfabient				maxy--;
538205693Sfabient				if (y >= maxy)
539205693Sfabient					break;
540203790Sfabient				PMCSTAT_PRINTW("\n%*s", indentwidth, space);
541203790Sfabient				width = indentwidth + ns_len + is_len + vs_len;
542203790Sfabient			}
543203790Sfabient
544203790Sfabient			PMCSTAT_ATTRON(v_attrs);
545203790Sfabient			PMCSTAT_PRINTW("%s%s%s ", ns, is, vs);
546203790Sfabient			PMCSTAT_ATTROFF(v_attrs);
547203790Sfabient		}
548203790Sfabient	}
549203790Sfabient}
550203790Sfabient
551203790Sfabient/*
552203790Sfabient * Output top mode snapshot.
553203790Sfabient */
554203790Sfabient
555203790Sfabientvoid
556203790Sfabientpmcpl_ct_topdisplay(void)
557203790Sfabient{
558207755Sfabient	int y;
559206994Sfabient	struct pmcpl_ct_sample r, *rsamples;
560203790Sfabient
561206994Sfabient	rsamples = &r;
562206994Sfabient	pmcpl_ct_samples_root(rsamples);
563207755Sfabient	pmcpl_ct_node_cleartag();
564203790Sfabient
565207755Sfabient	PMCSTAT_PRINTW("%5.5s %s\n", "%SAMP", "CALLTREE");
566203790Sfabient
567207755Sfabient	y = 0;
568207755Sfabient	if (pmcpl_ct_node_dumptop(pmcstat_pmcinfilter,
569207755Sfabient	    pmcpl_ct_root, rsamples, 0, &y))
570207755Sfabient		PMCSTAT_PRINTW("...\n");
571207755Sfabient	pmcpl_ct_topscreen[1][y] = NULL;
572203790Sfabient
573207755Sfabient	pmcpl_ct_node_printtop(rsamples,
574207755Sfabient	    pmcstat_pmcinfilter, pmcstat_displayheight - 2);
575203790Sfabient
576206994Sfabient	pmcpl_ct_samples_free(rsamples);
577203790Sfabient}
578203790Sfabient
579203790Sfabient/*
580203790Sfabient * Handle top mode keypress.
581203790Sfabient */
582203790Sfabient
583203790Sfabientint
584203790Sfabientpmcpl_ct_topkeypress(int c, WINDOW *w)
585203790Sfabient{
586203790Sfabient
587203790Sfabient	switch (c) {
588203790Sfabient	case 'f':
589203790Sfabient		pmcstat_skiplink = !pmcstat_skiplink;
590227524Sobrien		wprintw(w, "skip empty link %s",
591227524Sobrien		    pmcstat_skiplink ? "on" : "off");
592203790Sfabient		break;
593203790Sfabient	}
594203790Sfabient
595203790Sfabient	return 0;
596203790Sfabient}
597203790Sfabient
598203790Sfabient/*
599203790Sfabient * Look for a callgraph node associated with pmc `pmcid' in the global
600203790Sfabient * hash table that corresponds to the given `pc' value in the process map
601203790Sfabient * `ppm'.
602203790Sfabient */
603203790Sfabient
604233611Sfabientstatic void
605233611Sfabientpmcpl_ct_node_update(struct pmcpl_ct_node *parent,
606233611Sfabient    struct pmcpl_ct_node *child, int pmcin, unsigned v, int cd)
607203790Sfabient{
608203790Sfabient	struct pmcpl_ct_arc *arc;
609203790Sfabient	int i;
610203790Sfabient
611203790Sfabient	assert(parent != NULL);
612203790Sfabient
613233611Sfabient	/*
614233611Sfabient	 * Find related arc in parent node and
615233611Sfabient	 * increment the sample count.
616233611Sfabient	 */
617233611Sfabient	for (i = 0; i < parent->pct_narc; i++) {
618233611Sfabient		if (parent->pct_arc[i].pcta_child == child) {
619233611Sfabient			arc = &parent->pct_arc[i];
620233611Sfabient			pmcpl_ct_samples_grow(&arc->pcta_samples);
621233611Sfabient			arc->pcta_samples.sb[pmcin] += v;
622233611Sfabient			/* Estimate call count. */
623233611Sfabient			if (cd) {
624233611Sfabient			pmcpl_ct_samples_grow(&arc->pcta_callid);
625233611Sfabient			if (pmcpl_ct_callid.sb[pmcin] -
626233611Sfabient			    arc->pcta_callid.sb[pmcin] > 1)
627233611Sfabient				arc->pcta_call++;
628233611Sfabient			arc->pcta_callid.sb[pmcin] =
629233611Sfabient			    pmcpl_ct_callid.sb[pmcin];
630233611Sfabient			}
631233611Sfabient			return;
632233611Sfabient		}
633233611Sfabient	}
634203790Sfabient
635203790Sfabient	/*
636233611Sfabient	 * No arc found for us, add ourself to the parent.
637203790Sfabient	 */
638233611Sfabient	pmcpl_ct_arc_grow(parent->pct_narc,
639233611Sfabient	    &parent->pct_arc_c, &parent->pct_arc);
640233611Sfabient	arc = &parent->pct_arc[parent->pct_narc];
641233611Sfabient	pmcpl_ct_samples_grow(&arc->pcta_samples);
642233611Sfabient	arc->pcta_samples.sb[pmcin] = v;
643233611Sfabient	arc->pcta_call = 1;
644233611Sfabient	if (cd) {
645233611Sfabient		pmcpl_ct_samples_grow(&arc->pcta_callid);
646233611Sfabient		arc->pcta_callid.sb[pmcin] = pmcpl_ct_callid.sb[pmcin];
647233611Sfabient	}
648233611Sfabient	arc->pcta_child = child;
649233611Sfabient	parent->pct_narc++;
650233611Sfabient}
651203790Sfabient
652233611Sfabient/*
653233611Sfabient * Lookup by image/pc.
654233611Sfabient */
655233611Sfabient
656233611Sfabientstatic struct pmcpl_ct_node *
657233611Sfabientpmcpl_ct_node_hash_lookup(struct pmcstat_image *image, uintfptr_t pc,
658233611Sfabient    struct pmcstat_symbol *sym, char *fl, char *fn)
659233611Sfabient{
660233611Sfabient	int i;
661233611Sfabient	unsigned int hash;
662233611Sfabient	struct pmcpl_ct_node *ct;
663233611Sfabient	struct pmcpl_ct_node_hash *h;
664233611Sfabient	pmcstat_interned_string	ifl, ifn;
665233611Sfabient
666233611Sfabient	if (fn != NULL) {
667233611Sfabient		ifl = pmcstat_string_intern(fl);
668233611Sfabient		ifn = pmcstat_string_intern(fn);
669233611Sfabient	} else {
670233611Sfabient		ifl = 0;
671233611Sfabient		ifn = 0;
672233611Sfabient	}
673233611Sfabient
674203790Sfabient	for (hash = i = 0; i < (int)sizeof(uintfptr_t); i++)
675203790Sfabient		hash += (pc >> i) & 0xFF;
676203790Sfabient
677203790Sfabient	hash &= PMCSTAT_HASH_MASK;
678203790Sfabient
679233611Sfabient	STAILQ_FOREACH(h, &pmcpl_ct_node_hash[hash], pch_next) {
680203790Sfabient		ct = h->pch_ctnode;
681203790Sfabient
682203790Sfabient		assert(ct != NULL);
683203790Sfabient
684203790Sfabient		if (ct->pct_image == image && ct->pct_func == pc) {
685233611Sfabient			if (fn == NULL)
686233611Sfabient				return (ct);
687233611Sfabient			if (ct->pct_type == PMCPL_PCT_NAME &&
688233611Sfabient			    ct->pct_ifl == ifl && ct->pct_ifn == ifn)
689233611Sfabient				return (ct);
690203790Sfabient		}
691203790Sfabient	}
692203790Sfabient
693203790Sfabient	/*
694203790Sfabient	 * We haven't seen this (pmcid, pc) tuple yet, so allocate a
695203790Sfabient	 * new callgraph node and a new hash table entry for it.
696203790Sfabient	 */
697233611Sfabient	ct = pmcpl_ct_node_allocate();
698203790Sfabient	if ((h = malloc(sizeof(*h))) == NULL)
699203790Sfabient		err(EX_OSERR, "ERROR: Could not allocate callgraph node");
700203790Sfabient
701233611Sfabient	if (fn != NULL) {
702233611Sfabient		ct->pct_type = PMCPL_PCT_NAME;
703233611Sfabient		ct->pct_ifl = ifl;
704233611Sfabient		ct->pct_ifn = ifn;
705233611Sfabient	} else
706233611Sfabient		ct->pct_type = PMCPL_PCT_ADDR;
707233611Sfabient	ct->pct_image = image;
708233611Sfabient	ct->pct_func = pc;
709233611Sfabient	ct->pct_sym = sym;
710233611Sfabient
711203790Sfabient	h->pch_ctnode = ct;
712233611Sfabient	STAILQ_INSERT_HEAD(&pmcpl_ct_node_hash[hash], h, pch_next);
713203790Sfabient	return (ct);
714203790Sfabient}
715203790Sfabient
716203790Sfabient/*
717203790Sfabient * Record a callchain.
718203790Sfabient */
719203790Sfabient
720203790Sfabientvoid
721203790Sfabientpmcpl_ct_process(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr,
722203790Sfabient    uint32_t nsamples, uintfptr_t *cc, int usermode, uint32_t cpu)
723203790Sfabient{
724233611Sfabient	int i, n, pmcin;
725233611Sfabient	uintfptr_t pc, loadaddress;
726233611Sfabient	struct pmcstat_image *image;
727233611Sfabient	struct pmcstat_symbol *sym;
728203790Sfabient	struct pmcstat_pcmap *ppm[PMC_CALLCHAIN_DEPTH_MAX];
729203790Sfabient	struct pmcstat_process *km;
730233611Sfabient	struct pmcpl_ct_node *ct;
731233611Sfabient	struct pmcpl_ct_node *ctl[PMC_CALLCHAIN_DEPTH_MAX+1];
732203790Sfabient
733203790Sfabient	(void) cpu;
734203790Sfabient
735203790Sfabient	assert(nsamples>0 && nsamples<=PMC_CALLCHAIN_DEPTH_MAX);
736203790Sfabient
737203790Sfabient	/* Get the PMC index. */
738203790Sfabient	pmcin = pmcr->pr_pmcin;
739203790Sfabient
740203790Sfabient	/*
741203790Sfabient	 * Validate mapping for the callchain.
742203790Sfabient	 * Go from bottom to first invalid entry.
743203790Sfabient	 */
744203790Sfabient	km = pmcstat_kernproc;
745203790Sfabient	for (n = 0; n < (int)nsamples; n++) {
746203790Sfabient		ppm[n] = pmcstat_process_find_map(usermode ?
747203790Sfabient		    pp : km, cc[n]);
748203790Sfabient		if (ppm[n] == NULL) {
749203790Sfabient			/* Detect full frame capture (kernel + user). */
750203790Sfabient			if (!usermode) {
751203790Sfabient				ppm[n] = pmcstat_process_find_map(pp, cc[n]);
752203790Sfabient				if (ppm[n] != NULL)
753203790Sfabient					km = pp;
754203790Sfabient			}
755203790Sfabient		}
756203790Sfabient		if (ppm[n] == NULL)
757203790Sfabient			break;
758203790Sfabient	}
759203790Sfabient	if (n-- == 0) {
760203790Sfabient		pmcstat_stats.ps_callchain_dubious_frames++;
761206090Sfabient		pmcr->pr_dubious_frames++;
762203790Sfabient		return;
763203790Sfabient	}
764203790Sfabient
765203790Sfabient	/* Increase the call generation counter. */
766203790Sfabient	pmcpl_ct_samples_grow(&pmcpl_ct_callid);
767203790Sfabient	pmcpl_ct_callid.sb[pmcin]++;
768203790Sfabient
769203790Sfabient	/*
770233611Sfabient	 * Build node list.
771203790Sfabient	 */
772233611Sfabient	ctl[0] = pmcpl_ct_root;
773233611Sfabient	for (i = 1; n >= 0; n--) {
774233611Sfabient		image = ppm[n]->ppm_image;
775233611Sfabient		loadaddress = ppm[n]->ppm_lowpc +
776233611Sfabient		    image->pi_vaddr - image->pi_start;
777233611Sfabient		/* Convert to an offset in the image. */
778233611Sfabient		pc = cc[n] - loadaddress;
779233611Sfabient		/*
780233611Sfabient		 * Try determine the function at this offset.  If we can't
781233611Sfabient		 * find a function round leave the `pc' value alone.
782233611Sfabient		 */
783233611Sfabient		if ((sym = pmcstat_symbol_search(image, pc)) != NULL)
784233611Sfabient			pc = sym->ps_start;
785233611Sfabient		else
786233611Sfabient			pmcstat_stats.ps_samples_unknown_function++;
787233611Sfabient
788233611Sfabient		ct = pmcpl_ct_node_hash_lookup(image, pc, sym, NULL, NULL);
789233611Sfabient		if (ct == NULL) {
790203790Sfabient			pmcstat_stats.ps_callchain_dubious_frames++;
791203790Sfabient			continue;
792203790Sfabient		}
793233611Sfabient		ctl[i++] = ct;
794203790Sfabient	}
795233611Sfabient	/* No valid node found. */
796233611Sfabient	if (i == 1)
797233611Sfabient		return;
798233611Sfabient	n = i;
799203790Sfabient
800233611Sfabient	ct = ctl[0];
801233611Sfabient	for (i = 1; i < n; i++)
802233611Sfabient		pmcpl_ct_node_update(ctl[i-1], ctl[i], pmcin, 1, 1);
803233611Sfabient
804203790Sfabient	/*
805203790Sfabient	 * Increment the sample count for this PMC.
806203790Sfabient	 */
807233611Sfabient	pmcpl_ct_samples_grow(&ctl[n-1]->pct_samples);
808233611Sfabient	ctl[n-1]->pct_samples.sb[pmcin]++;
809203790Sfabient
810233611Sfabient	/* Update per instruction sample if required. */
811233611Sfabient	if (args.pa_ctdumpinstr)
812233611Sfabient		pmcpl_ct_instr_add(ctl[n-1], pmcin, cc[0] -
813233611Sfabient		    (ppm[0]->ppm_lowpc + ppm[0]->ppm_image->pi_vaddr -
814233611Sfabient		     ppm[0]->ppm_image->pi_start), 1);
815233611Sfabient}
816233611Sfabient
817233611Sfabient/*
818233611Sfabient * Print node child cost.
819233611Sfabient */
820233611Sfabient
821233611Sfabientstatic void
822233611Sfabientpmcpl_ct_node_printchild(struct pmcpl_ct_node *ct, uintfptr_t paddr,
823233611Sfabient    int pline)
824233611Sfabient{
825233611Sfabient	int i, j, line;
826233611Sfabient	uintfptr_t addr;
827233611Sfabient	struct pmcpl_ct_node *child;
828233611Sfabient	char sourcefile[PATH_MAX];
829233611Sfabient	char funcname[PATH_MAX];
830233611Sfabient
831233611Sfabient	/*
832233611Sfabient	 * Child cost.
833233611Sfabient	 * TODO: attach child cost to the real position in the funtion.
834233611Sfabient	 * TODO: cfn=<fn> / call <ncall> addr(<fn>) / addr(call <fn>) <arccost>
835233611Sfabient	 */
836233611Sfabient	for (i=0 ; i<ct->pct_narc; i++) {
837233611Sfabient		child = ct->pct_arc[i].pcta_child;
838233611Sfabient		/* Object binary. */
839233611Sfabient		fprintf(args.pa_graphfile, "cob=%s\n",
840233611Sfabient		    pmcstat_string_unintern(child->pct_image->pi_fullpath));
841233611Sfabient		/* Child function name. */
842233611Sfabient		addr = child->pct_image->pi_vaddr + child->pct_func;
843233611Sfabient		line = 0;
844233611Sfabient		/* Child function source file. */
845233611Sfabient		if (child->pct_type == PMCPL_PCT_NAME) {
846233611Sfabient			fprintf(args.pa_graphfile, "cfi=%s\ncfn=%s\n",
847233611Sfabient			    pmcstat_string_unintern(child->pct_ifl),
848233611Sfabient			    pmcstat_string_unintern(child->pct_ifn));
849233611Sfabient		} else if (pmcstat_image_addr2line(child->pct_image, addr,
850233611Sfabient		    sourcefile, sizeof(sourcefile), &line,
851233611Sfabient		    funcname, sizeof(funcname))) {
852233611Sfabient			fprintf(args.pa_graphfile, "cfi=%s\ncfn=%s\n",
853233611Sfabient				sourcefile, funcname);
854233611Sfabient		} else {
855233611Sfabient			if (child->pct_sym != NULL)
856233611Sfabient				fprintf(args.pa_graphfile,
857233611Sfabient				    "cfi=???\ncfn=%s\n",
858233611Sfabient				    pmcstat_string_unintern(
859233611Sfabient				        child->pct_sym->ps_name));
860233611Sfabient			else
861233611Sfabient				fprintf(args.pa_graphfile,
862233611Sfabient				    "cfi=???\ncfn=%p\n", (void *)addr);
863233611Sfabient		}
864233611Sfabient
865233611Sfabient		/* Child function address, line and call count. */
866233611Sfabient		fprintf(args.pa_graphfile, "calls=%u %p %u\n",
867233611Sfabient		    ct->pct_arc[i].pcta_call, (void *)addr, line);
868233611Sfabient
869233611Sfabient		/*
870233611Sfabient		 * Call address, line, sample.
871233611Sfabient		 * TODO: Associate call address to the right location.
872233611Sfabient		 */
873233611Sfabient		fprintf(args.pa_graphfile, "%p %u", (void *)paddr, pline);
874233611Sfabient		for (j = 0; j<pmcstat_npmcs; j++)
875233611Sfabient			fprintf(args.pa_graphfile, " %u",
876233611Sfabient			    PMCPL_CT_SAMPLE(j, &ct->pct_arc[i].pcta_samples));
877233611Sfabient		fprintf(args.pa_graphfile, "\n");
878203790Sfabient	}
879203790Sfabient}
880203790Sfabient
881203790Sfabient/*
882203790Sfabient * Print node self cost.
883203790Sfabient */
884203790Sfabient
885203790Sfabientstatic void
886203790Sfabientpmcpl_ct_node_printself(struct pmcpl_ct_node *ct)
887203790Sfabient{
888233611Sfabient	int i, j, fline, line;
889233611Sfabient	uintfptr_t faddr, addr;
890203790Sfabient	char sourcefile[PATH_MAX];
891203790Sfabient	char funcname[PATH_MAX];
892203790Sfabient
893203790Sfabient	/*
894203790Sfabient	 * Object binary.
895203790Sfabient	 */
896233611Sfabient	fprintf(args.pa_graphfile, "ob=%s\n",
897233611Sfabient	    pmcstat_string_unintern(ct->pct_image->pi_fullpath));
898203790Sfabient
899203790Sfabient	/*
900203790Sfabient	 * Function name.
901203790Sfabient	 */
902233611Sfabient	faddr = ct->pct_image->pi_vaddr + ct->pct_func;
903233611Sfabient	fline = 0;
904233611Sfabient	if (ct->pct_type == PMCPL_PCT_NAME) {
905233611Sfabient		fprintf(args.pa_graphfile, "fl=%s\nfn=%s\n",
906233611Sfabient		    pmcstat_string_unintern(ct->pct_ifl),
907233611Sfabient		    pmcstat_string_unintern(ct->pct_ifn));
908233611Sfabient	} else if (pmcstat_image_addr2line(ct->pct_image, faddr,
909233611Sfabient	    sourcefile, sizeof(sourcefile), &fline,
910203790Sfabient	    funcname, sizeof(funcname))) {
911233611Sfabient		fprintf(args.pa_graphfile, "fl=%s\nfn=%s\n",
912233611Sfabient		    sourcefile, funcname);
913203790Sfabient	} else {
914233611Sfabient		if (ct->pct_sym != NULL)
915233611Sfabient			fprintf(args.pa_graphfile, "fl=???\nfn=%s\n",
916233611Sfabient			    pmcstat_string_unintern(ct->pct_sym->ps_name));
917203790Sfabient		else
918233611Sfabient			fprintf(args.pa_graphfile, "fl=???\nfn=%p\n",
919203790Sfabient			    (void *)(ct->pct_image->pi_vaddr + ct->pct_func));
920203790Sfabient	}
921203790Sfabient
922203790Sfabient	/*
923203790Sfabient	 * Self cost.
924203790Sfabient	 */
925203790Sfabient	if (ct->pct_ninstr > 0) {
926233611Sfabient		/*
927233611Sfabient		 * Per location cost.
928233611Sfabient		 */
929203790Sfabient		for (i = 0; i < ct->pct_ninstr; i++) {
930203790Sfabient			addr = ct->pct_image->pi_vaddr +
931203790Sfabient			    ct->pct_instr[i].pctf_func;
932203790Sfabient			line = 0;
933233611Sfabient			pmcstat_image_addr2line(ct->pct_image, addr,
934203790Sfabient			    sourcefile, sizeof(sourcefile), &line,
935233611Sfabient			    funcname, sizeof(funcname));
936233611Sfabient			fprintf(args.pa_graphfile, "%p %u",
937233611Sfabient			    (void *)addr, line);
938203790Sfabient			for (j = 0; j<pmcstat_npmcs; j++)
939203790Sfabient				fprintf(args.pa_graphfile, " %u",
940203790Sfabient				    PMCPL_CT_SAMPLE(j,
941203790Sfabient				    &ct->pct_instr[i].pctf_samples));
942203790Sfabient			fprintf(args.pa_graphfile, "\n");
943203790Sfabient		}
944203790Sfabient	} else {
945233611Sfabient		/* Global cost function cost. */
946233611Sfabient		fprintf(args.pa_graphfile, "%p %u", (void *)faddr, fline);
947203790Sfabient		for (i = 0; i<pmcstat_npmcs ; i++)
948203790Sfabient			fprintf(args.pa_graphfile, " %u",
949203790Sfabient			    PMCPL_CT_SAMPLE(i, &ct->pct_samples));
950203790Sfabient		fprintf(args.pa_graphfile, "\n");
951203790Sfabient	}
952233611Sfabient
953233611Sfabient	pmcpl_ct_node_printchild(ct, faddr, fline);
954203790Sfabient}
955203790Sfabient
956233611Sfabientstatic void
957233611Sfabientpmcpl_ct_printnode(struct pmcpl_ct_node *ct)
958233611Sfabient{
959233611Sfabient	int i;
960233611Sfabient
961233611Sfabient	if (ct == pmcpl_ct_root) {
962233611Sfabient		fprintf(args.pa_graphfile, "fn=root\n");
963233611Sfabient		fprintf(args.pa_graphfile, "0x0 1");
964233611Sfabient		for (i = 0; i<pmcstat_npmcs ; i++)
965233611Sfabient			fprintf(args.pa_graphfile, " 0");
966233611Sfabient		fprintf(args.pa_graphfile, "\n");
967233611Sfabient		pmcpl_ct_node_printchild(ct, 0, 0);
968233611Sfabient	} else
969233611Sfabient		pmcpl_ct_node_printself(ct);
970233611Sfabient}
971233611Sfabient
972203790Sfabient/*
973233611Sfabient * Breadth first traversal.
974203790Sfabient */
975203790Sfabient
976203790Sfabientstatic void
977233611Sfabientpmcpl_ct_bfs(struct pmcpl_ct_node *ct)
978203790Sfabient{
979233611Sfabient	int i;
980233611Sfabient	struct pmcpl_ct_node_hash *pch, *pchc;
981203790Sfabient	struct pmcpl_ct_node *child;
982233611Sfabient	STAILQ_HEAD(,pmcpl_ct_node_hash) q;
983233611Sfabient
984233611Sfabient	STAILQ_INIT(&q);
985233611Sfabient	if ((pch = malloc(sizeof(*pch))) == NULL)
986233611Sfabient		err(EX_OSERR, "ERROR: Cannot allocate queue");
987233611Sfabient	pch->pch_ctnode = ct;
988233611Sfabient	STAILQ_INSERT_TAIL(&q, pch, pch_next);
989233611Sfabient	ct->pct_color = PMCPL_PCT_BLACK;
990233611Sfabient
991233611Sfabient	while (!STAILQ_EMPTY(&q)) {
992233611Sfabient		pch = STAILQ_FIRST(&q);
993233611Sfabient		STAILQ_REMOVE_HEAD(&q, pch_next);
994233611Sfabient		pmcpl_ct_printnode(pch->pch_ctnode);
995233611Sfabient		for (i = 0; i<pch->pch_ctnode->pct_narc; i++) {
996233611Sfabient			child = pch->pch_ctnode->pct_arc[i].pcta_child;
997233611Sfabient			if (child->pct_color == PMCPL_PCT_WHITE) {
998233611Sfabient				child->pct_color = PMCPL_PCT_BLACK;
999233611Sfabient				if ((pchc = malloc(sizeof(*pchc))) == NULL)
1000233611Sfabient					err(EX_OSERR,
1001233611Sfabient					    "ERROR: Cannot allocate queue");
1002233611Sfabient				pchc->pch_ctnode = child;
1003233611Sfabient				STAILQ_INSERT_TAIL(&q, pchc, pch_next);
1004233611Sfabient			}
1005233611Sfabient		}
1006233611Sfabient		free(pch);
1007233611Sfabient	}
1008233611Sfabient}
1009233611Sfabient
1010233611Sfabient/*
1011233611Sfabient * Detect and fix inlined location.
1012233611Sfabient */
1013233611Sfabient
1014233611Sfabientstatic void
1015233611Sfabient_pmcpl_ct_expand_inline(struct pmcpl_ct_node *ct)
1016233611Sfabient{
1017233611Sfabient	int i, j;
1018233611Sfabient	unsigned fline, line, v;
1019233611Sfabient	uintfptr_t faddr, addr, pc;
1020203790Sfabient	char sourcefile[PATH_MAX];
1021233611Sfabient	char ffuncname[PATH_MAX], funcname[PATH_MAX];
1022233611Sfabient	char buffer[PATH_MAX];
1023233611Sfabient	struct pmcpl_ct_node *child;
1024203790Sfabient
1025203790Sfabient	/*
1026233611Sfabient	 * Resolve parent and compare to each instr location.
1027203790Sfabient	 */
1028233611Sfabient	faddr = ct->pct_image->pi_vaddr + ct->pct_func;
1029233611Sfabient	fline = 0;
1030233611Sfabient	if (!pmcstat_image_addr2line(ct->pct_image, faddr,
1031233611Sfabient	    sourcefile, sizeof(sourcefile), &fline,
1032233611Sfabient	    ffuncname, sizeof(ffuncname)))
1033233611Sfabient		return;
1034203790Sfabient
1035233611Sfabient	for (i = 0; i < ct->pct_ninstr; i++) {
1036233611Sfabient		addr = ct->pct_image->pi_vaddr +
1037233611Sfabient		    ct->pct_instr[i].pctf_func;
1038233611Sfabient		line = 0;
1039233611Sfabient		if (!pmcstat_image_addr2line(ct->pct_image, addr,
1040203790Sfabient		    sourcefile, sizeof(sourcefile), &line,
1041233611Sfabient		    funcname, sizeof(funcname)))
1042233611Sfabient			continue;
1043203790Sfabient
1044233611Sfabient		if (strcmp(funcname, ffuncname) == 0)
1045233611Sfabient			continue;
1046203790Sfabient
1047233611Sfabient		/*
1048233611Sfabient		 * - Lookup/create inline node by function name.
1049233611Sfabient		 * - Move instr PMCs to the inline node.
1050233611Sfabient		 * - Link nodes.
1051233611Sfabient		 * The lookup create a specific node per image/pc.
1052233611Sfabient		 */
1053233611Sfabient		if (args.pa_verbosity >= 2)
1054233611Sfabient			fprintf(args.pa_printfile,
1055233611Sfabient			    "WARNING: inlined function at %p %s in %s\n",
1056233611Sfabient			    (void *)addr, funcname, ffuncname);
1057233611Sfabient
1058233611Sfabient		snprintf(buffer, sizeof(buffer), "%s@%s",
1059233611Sfabient			funcname, ffuncname);
1060233611Sfabient		child = pmcpl_ct_node_hash_lookup(ct->pct_image,
1061233611Sfabient		    ct->pct_func, ct->pct_sym, sourcefile, buffer);
1062233611Sfabient		assert(child != NULL);
1063233611Sfabient		pc = ct->pct_instr[i].pctf_func;
1064233611Sfabient		for (j = 0; j<pmcstat_npmcs; j++) {
1065233611Sfabient			v = PMCPL_CT_SAMPLE(j,
1066233611Sfabient			    &ct->pct_instr[i].pctf_samples);
1067233611Sfabient			if (v == 0)
1068233611Sfabient				continue;
1069233611Sfabient			pmcpl_ct_instr_add(child, j, pc, v);
1070233611Sfabient			pmcpl_ct_node_update(ct, child, j, v, 0);
1071233611Sfabient			if (j < ct->pct_samples.npmcs)
1072233611Sfabient				ct->pct_samples.sb[j] -=
1073233611Sfabient				    ct->pct_instr[i].pctf_samples.sb[j];
1074233611Sfabient			ct->pct_instr[i].pctf_samples.sb[j] = 0;
1075203790Sfabient		}
1076203790Sfabient	}
1077203790Sfabient}
1078203790Sfabient
1079233611Sfabientstatic void
1080233611Sfabientpmcpl_ct_expand_inline(void)
1081233611Sfabient{
1082233611Sfabient	int i;
1083233611Sfabient	struct pmcpl_ct_node_hash *pch;
1084233611Sfabient
1085233611Sfabient	if (!args.pa_ctdumpinstr)
1086233611Sfabient		return;
1087233611Sfabient
1088233611Sfabient	for (i = 0; i < PMCSTAT_NHASH; i++)
1089233611Sfabient		STAILQ_FOREACH(pch, &pmcpl_ct_node_hash[i], pch_next)
1090233611Sfabient			if (pch->pch_ctnode->pct_type == PMCPL_PCT_ADDR)
1091233611Sfabient				_pmcpl_ct_expand_inline(pch->pch_ctnode);
1092233611Sfabient}
1093233611Sfabient
1094203790Sfabient/*
1095203790Sfabient * Clean the PMC name for Kcachegrind formula
1096203790Sfabient */
1097203790Sfabient
1098203790Sfabientstatic void
1099203790Sfabientpmcpl_ct_fixup_pmcname(char *s)
1100203790Sfabient{
1101203790Sfabient	char *p;
1102203790Sfabient
1103203790Sfabient	for (p = s; *p; p++)
1104203790Sfabient		if (!isalnum(*p))
1105203790Sfabient			*p = '_';
1106203790Sfabient}
1107203790Sfabient
1108203790Sfabient/*
1109203790Sfabient * Print a calltree (KCachegrind) for all PMCs.
1110203790Sfabient */
1111203790Sfabient
1112203790Sfabientstatic void
1113203790Sfabientpmcpl_ct_print(void)
1114203790Sfabient{
1115233611Sfabient	int i;
1116233611Sfabient	char name[40];
1117203790Sfabient	struct pmcpl_ct_sample rsamples;
1118203790Sfabient
1119203790Sfabient	pmcpl_ct_samples_root(&rsamples);
1120233611Sfabient	pmcpl_ct_expand_inline();
1121203790Sfabient
1122203790Sfabient	fprintf(args.pa_graphfile,
1123203790Sfabient		"version: 1\n"
1124203790Sfabient		"creator: pmcstat\n"
1125203790Sfabient		"positions: instr line\n"
1126203790Sfabient		"events:");
1127203790Sfabient	for (i=0; i<pmcstat_npmcs; i++) {
1128203790Sfabient		snprintf(name, sizeof(name), "%s_%d",
1129203790Sfabient		    pmcstat_pmcindex_to_name(i), i);
1130203790Sfabient		pmcpl_ct_fixup_pmcname(name);
1131203790Sfabient		fprintf(args.pa_graphfile, " %s", name);
1132203790Sfabient	}
1133203790Sfabient	fprintf(args.pa_graphfile, "\nsummary:");
1134203790Sfabient	for (i=0; i<pmcstat_npmcs ; i++)
1135203790Sfabient		fprintf(args.pa_graphfile, " %u",
1136203790Sfabient		    PMCPL_CT_SAMPLE(i, &rsamples));
1137203790Sfabient	fprintf(args.pa_graphfile, "\n");
1138233611Sfabient	pmcpl_ct_bfs(pmcpl_ct_root);
1139203790Sfabient	pmcpl_ct_samples_free(&rsamples);
1140203790Sfabient}
1141203790Sfabient
1142203790Sfabientint
1143203790Sfabientpmcpl_ct_configure(char *opt)
1144203790Sfabient{
1145203790Sfabient
1146203790Sfabient	if (strncmp(opt, "skiplink=", 9) == 0) {
1147203790Sfabient		pmcstat_skiplink = atoi(opt+9);
1148203790Sfabient	} else
1149203790Sfabient		return (0);
1150203790Sfabient
1151203790Sfabient	return (1);
1152203790Sfabient}
1153203790Sfabient
1154203790Sfabientint
1155203790Sfabientpmcpl_ct_init(void)
1156203790Sfabient{
1157203790Sfabient	int i;
1158203790Sfabient
1159233611Sfabient	pmcpl_ct_root = pmcpl_ct_node_allocate();
1160203790Sfabient
1161203790Sfabient	for (i = 0; i < PMCSTAT_NHASH; i++)
1162233611Sfabient		STAILQ_INIT(&pmcpl_ct_node_hash[i]);
1163203790Sfabient
1164203790Sfabient	pmcpl_ct_samples_init(&pmcpl_ct_callid);
1165203790Sfabient
1166203790Sfabient	return (0);
1167203790Sfabient}
1168203790Sfabient
1169203790Sfabientvoid
1170203790Sfabientpmcpl_ct_shutdown(FILE *mf)
1171203790Sfabient{
1172203790Sfabient	int i;
1173203790Sfabient	struct pmcpl_ct_node_hash *pch, *pchtmp;
1174203790Sfabient
1175203790Sfabient	(void) mf;
1176203790Sfabient
1177203790Sfabient	if (args.pa_flags & FLAG_DO_CALLGRAPHS)
1178203790Sfabient		pmcpl_ct_print();
1179203790Sfabient
1180203790Sfabient	/*
1181203790Sfabient	 * Free memory.
1182203790Sfabient	 */
1183203790Sfabient
1184203790Sfabient	for (i = 0; i < PMCSTAT_NHASH; i++) {
1185233611Sfabient		STAILQ_FOREACH_SAFE(pch, &pmcpl_ct_node_hash[i], pch_next,
1186203790Sfabient		    pchtmp) {
1187203790Sfabient			pmcpl_ct_node_free(pch->pch_ctnode);
1188203790Sfabient			free(pch);
1189203790Sfabient		}
1190203790Sfabient	}
1191203790Sfabient
1192203790Sfabient	pmcpl_ct_node_free(pmcpl_ct_root);
1193203790Sfabient	pmcpl_ct_root = NULL;
1194203790Sfabient
1195203790Sfabient	pmcpl_ct_samples_free(&pmcpl_ct_callid);
1196203790Sfabient}
1197203790Sfabient
1198