1203790Sfabient/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
4233611Sfabient * Copyright (c) 2012, Fabien Thomas
5203790Sfabient * All rights reserved.
6203790Sfabient *
7203790Sfabient * Redistribution and use in source and binary forms, with or without
8203790Sfabient * modification, are permitted provided that the following conditions
9203790Sfabient * are met:
10203790Sfabient * 1. Redistributions of source code must retain the above copyright
11203790Sfabient *    notice, this list of conditions and the following disclaimer.
12203790Sfabient * 2. Redistributions in binary form must reproduce the above copyright
13203790Sfabient *    notice, this list of conditions and the following disclaimer in the
14203790Sfabient *    documentation and/or other materials provided with the distribution.
15203790Sfabient *
16203790Sfabient * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17203790Sfabient * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18203790Sfabient * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19203790Sfabient * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20203790Sfabient * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21203790Sfabient * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22203790Sfabient * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23203790Sfabient * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24203790Sfabient * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25203790Sfabient * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26203790Sfabient * SUCH DAMAGE.
27203790Sfabient */
28203790Sfabient
29203790Sfabient/*
30203790Sfabient * Process hwpmc(4) samples as calltree.
31203790Sfabient *
32203790Sfabient * Output file format compatible with Kcachegrind (kdesdk).
33203790Sfabient * Handle top mode with a sorted tree display.
34203790Sfabient */
35203790Sfabient
36203790Sfabient#include <sys/cdefs.h>
37203790Sfabient__FBSDID("$FreeBSD: stable/11/usr.sbin/pmcstat/pmcpl_calltree.c 330449 2018-03-05 07:26:05Z eadler $");
38203790Sfabient
39203790Sfabient#include <sys/param.h>
40203790Sfabient#include <sys/endian.h>
41203790Sfabient#include <sys/queue.h>
42203790Sfabient
43203790Sfabient#include <assert.h>
44203790Sfabient#include <curses.h>
45203790Sfabient#include <ctype.h>
46203790Sfabient#include <err.h>
47203790Sfabient#include <errno.h>
48203790Sfabient#include <fcntl.h>
49203790Sfabient#include <pmc.h>
50203790Sfabient#include <pmclog.h>
51203790Sfabient#include <stdint.h>
52203790Sfabient#include <stdio.h>
53203790Sfabient#include <stdlib.h>
54203790Sfabient#include <string.h>
55203790Sfabient#include <unistd.h>
56203790Sfabient#include <sysexits.h>
57203790Sfabient
58203790Sfabient#include "pmcstat.h"
59203790Sfabient#include "pmcstat_log.h"
60203790Sfabient#include "pmcstat_top.h"
61203790Sfabient#include "pmcpl_calltree.h"
62203790Sfabient
63233611Sfabient#define	PMCPL_CT_GROWSIZE	4
64203790Sfabient
65203790Sfabientstatic int pmcstat_skiplink = 0;
66203790Sfabient
67203790Sfabientstruct pmcpl_ct_node;
68203790Sfabient
69203790Sfabient/* Get the sample value for PMC a. */
70233611Sfabient#define	PMCPL_CT_SAMPLE(a, b) \
71203790Sfabient	((a) < (b)->npmcs ? (b)->sb[a] : 0)
72203790Sfabient
73203790Sfabient/* Get the sample value in percent related to rsamples. */
74233611Sfabient#define	PMCPL_CT_SAMPLEP(a, b) \
75203790Sfabient	(PMCPL_CT_SAMPLE(a, b) * 100.0 / rsamples->sb[a])
76203790Sfabient
77203790Sfabientstruct pmcpl_ct_sample {
78203790Sfabient	int		npmcs;		/* Max pmc index available. */
79203790Sfabient	unsigned	*sb;		/* Sample buffer for 0..npmcs. */
80203790Sfabient};
81203790Sfabient
82203790Sfabientstruct pmcpl_ct_arc {
83203790Sfabient	struct pmcpl_ct_sample	pcta_samples;
84203790Sfabient	struct pmcpl_ct_sample	pcta_callid;
85203790Sfabient	unsigned		pcta_call;
86203790Sfabient	struct pmcpl_ct_node	*pcta_child;
87203790Sfabient};
88203790Sfabient
89203790Sfabientstruct pmcpl_ct_instr {
90203790Sfabient	uintfptr_t		pctf_func;
91203790Sfabient	struct pmcpl_ct_sample	pctf_samples;
92203790Sfabient};
93203790Sfabient
94203790Sfabient/*
95203790Sfabient * Each calltree node is tracked by a pmcpl_ct_node struct.
96203790Sfabient */
97203790Sfabientstruct pmcpl_ct_node {
98203790Sfabient	struct pmcstat_image	*pct_image;
99203790Sfabient	uintfptr_t		pct_func;
100233611Sfabient
101233611Sfabient	struct pmcstat_symbol	*pct_sym;
102233611Sfabient	pmcstat_interned_string	pct_ifl;
103233611Sfabient	pmcstat_interned_string	pct_ifn;
104233611Sfabient
105203790Sfabient	struct pmcpl_ct_sample	pct_samples;
106203790Sfabient
107203790Sfabient	int			pct_narc;
108203790Sfabient	int			pct_arc_c;
109203790Sfabient	struct pmcpl_ct_arc 	*pct_arc;
110203790Sfabient
111203790Sfabient	/* TODO: optimize for large number of items. */
112203790Sfabient	int			pct_ninstr;
113203790Sfabient	int			pct_instr_c;
114203790Sfabient	struct pmcpl_ct_instr	*pct_instr;
115233611Sfabient
116233611Sfabient#define PMCPL_PCT_ADDR	0
117233611Sfabient#define PMCPL_PCT_NAME	1
118233611Sfabient	char			pct_type;
119233611Sfabient#define	PMCPL_PCT_WHITE	0
120233611Sfabient#define	PMCPL_PCT_GREY	1
121233611Sfabient#define	PMCPL_PCT_BLACK	2
122233611Sfabient	char			pct_color;
123203790Sfabient};
124203790Sfabient
125203790Sfabientstruct pmcpl_ct_node_hash {
126203790Sfabient	struct pmcpl_ct_node  *pch_ctnode;
127233611Sfabient	STAILQ_ENTRY(pmcpl_ct_node_hash) pch_next;
128203790Sfabient};
129203790Sfabient
130241737Sedstatic struct pmcpl_ct_sample pmcpl_ct_callid;
131203790Sfabient
132233611Sfabient#define	PMCPL_CT_MAXCOL		PMC_CALLCHAIN_DEPTH_MAX
133233611Sfabient#define	PMCPL_CT_MAXLINE	1024	/* TODO: dynamic. */
134203790Sfabient
135207755Sfabientstruct pmcpl_ct_line {
136207755Sfabient	unsigned	ln_sum;
137207755Sfabient	unsigned	ln_index;
138207755Sfabient};
139207755Sfabient
140241737Sedstatic struct pmcpl_ct_line	pmcpl_ct_topmax[PMCPL_CT_MAXLINE+1];
141241737Sedstatic struct pmcpl_ct_node
142233611Sfabient    *pmcpl_ct_topscreen[PMCPL_CT_MAXCOL+1][PMCPL_CT_MAXLINE+1];
143207755Sfabient
144203790Sfabient/*
145203790Sfabient * All nodes indexed by function/image name are placed in a hash table.
146203790Sfabient */
147233611Sfabientstatic STAILQ_HEAD(,pmcpl_ct_node_hash) pmcpl_ct_node_hash[PMCSTAT_NHASH];
148203790Sfabient
149203790Sfabient/*
150203790Sfabient * Root node for the graph.
151203790Sfabient */
152203790Sfabientstatic struct pmcpl_ct_node *pmcpl_ct_root;
153203790Sfabient
154203790Sfabient/*
155203790Sfabient * Prototypes
156203790Sfabient */
157203790Sfabient
158203790Sfabient/*
159203790Sfabient * Initialize a samples.
160203790Sfabient */
161203790Sfabient
162203790Sfabientstatic void
163203790Sfabientpmcpl_ct_samples_init(struct pmcpl_ct_sample *samples)
164203790Sfabient{
165203790Sfabient
166203790Sfabient	samples->npmcs = 0;
167203790Sfabient	samples->sb = NULL;
168203790Sfabient}
169203790Sfabient
170203790Sfabient/*
171203790Sfabient * Free a samples.
172203790Sfabient */
173203790Sfabient
174203790Sfabientstatic void
175203790Sfabientpmcpl_ct_samples_free(struct pmcpl_ct_sample *samples)
176203790Sfabient{
177203790Sfabient
178203790Sfabient	samples->npmcs = 0;
179203790Sfabient	free(samples->sb);
180203790Sfabient	samples->sb = NULL;
181203790Sfabient}
182203790Sfabient
183203790Sfabient/*
184203790Sfabient * Grow a sample block to store pmcstat_npmcs PMCs.
185203790Sfabient */
186203790Sfabient
187203790Sfabientstatic void
188203790Sfabientpmcpl_ct_samples_grow(struct pmcpl_ct_sample *samples)
189203790Sfabient{
190317861Spfg	unsigned int npmcs;
191203790Sfabient
192203790Sfabient	/* Enough storage. */
193203790Sfabient	if (pmcstat_npmcs <= samples->npmcs)
194203790Sfabient                return;
195203790Sfabient
196203790Sfabient	npmcs = samples->npmcs +
197203790Sfabient	    max(pmcstat_npmcs - samples->npmcs, PMCPL_CT_GROWSIZE);
198317861Spfg	samples->sb = reallocarray(samples->sb, npmcs, sizeof(unsigned));
199203790Sfabient	if (samples->sb == NULL)
200203790Sfabient		errx(EX_SOFTWARE, "ERROR: out of memory");
201203790Sfabient	bzero((char *)samples->sb + samples->npmcs * sizeof(unsigned),
202203790Sfabient	    (npmcs - samples->npmcs) * sizeof(unsigned));
203203790Sfabient	samples->npmcs = npmcs;
204203790Sfabient}
205203790Sfabient
206203790Sfabient/*
207203790Sfabient * Compute the sum of all root arcs.
208203790Sfabient */
209203790Sfabient
210203790Sfabientstatic void
211203790Sfabientpmcpl_ct_samples_root(struct pmcpl_ct_sample *samples)
212203790Sfabient{
213203790Sfabient	int i, pmcin;
214203790Sfabient
215203790Sfabient	pmcpl_ct_samples_init(samples);
216203790Sfabient	pmcpl_ct_samples_grow(samples);
217203790Sfabient
218203790Sfabient	for (i = 0; i < pmcpl_ct_root->pct_narc; i++)
219203790Sfabient		for (pmcin = 0; pmcin < pmcstat_npmcs; pmcin++)
220203790Sfabient			samples->sb[pmcin] += PMCPL_CT_SAMPLE(pmcin,
221203790Sfabient			    &pmcpl_ct_root->pct_arc[i].pcta_samples);
222203790Sfabient}
223203790Sfabient
224203790Sfabient/*
225203790Sfabient * Grow the arc table.
226203790Sfabient */
227203790Sfabient
228203790Sfabientstatic void
229203790Sfabientpmcpl_ct_arc_grow(int cursize, int *maxsize, struct pmcpl_ct_arc **items)
230203790Sfabient{
231317861Spfg	unsigned int nmaxsize;
232203790Sfabient
233203790Sfabient	if (cursize < *maxsize)
234203790Sfabient		return;
235203790Sfabient
236203790Sfabient	nmaxsize = *maxsize + max(cursize + 1 - *maxsize, PMCPL_CT_GROWSIZE);
237317861Spfg	*items = reallocarray(*items, nmaxsize, sizeof(struct pmcpl_ct_arc));
238203790Sfabient	if (*items == NULL)
239203790Sfabient		errx(EX_SOFTWARE, "ERROR: out of memory");
240203790Sfabient	bzero((char *)*items + *maxsize * sizeof(struct pmcpl_ct_arc),
241203790Sfabient	    (nmaxsize - *maxsize) * sizeof(struct pmcpl_ct_arc));
242203790Sfabient	*maxsize = nmaxsize;
243203790Sfabient}
244203790Sfabient
245203790Sfabient/*
246203790Sfabient * Grow the instr table.
247203790Sfabient */
248203790Sfabient
249203790Sfabientstatic void
250203790Sfabientpmcpl_ct_instr_grow(int cursize, int *maxsize, struct pmcpl_ct_instr **items)
251203790Sfabient{
252317861Spfg	unsigned int nmaxsize;
253203790Sfabient
254203790Sfabient	if (cursize < *maxsize)
255203790Sfabient		return;
256203790Sfabient
257203790Sfabient	nmaxsize = *maxsize + max(cursize + 1 - *maxsize, PMCPL_CT_GROWSIZE);
258317861Spfg	*items = reallocarray(*items, nmaxsize, sizeof(struct pmcpl_ct_instr));
259203790Sfabient	if (*items == NULL)
260203790Sfabient		errx(EX_SOFTWARE, "ERROR: out of memory");
261203790Sfabient	bzero((char *)*items + *maxsize * sizeof(struct pmcpl_ct_instr),
262203790Sfabient	    (nmaxsize - *maxsize) * sizeof(struct pmcpl_ct_instr));
263203790Sfabient	*maxsize = nmaxsize;
264203790Sfabient}
265203790Sfabient
266203790Sfabient/*
267203790Sfabient * Add a new instruction sample to given node.
268203790Sfabient */
269203790Sfabient
270203790Sfabientstatic void
271233611Sfabientpmcpl_ct_instr_add(struct pmcpl_ct_node *ct, int pmcin,
272233611Sfabient    uintfptr_t pc, unsigned v)
273203790Sfabient{
274203790Sfabient	int i;
275203790Sfabient	struct pmcpl_ct_instr *in;
276203790Sfabient
277203790Sfabient	for (i = 0; i<ct->pct_ninstr; i++) {
278203790Sfabient		if (ct->pct_instr[i].pctf_func == pc) {
279203790Sfabient			in = &ct->pct_instr[i];
280203790Sfabient			pmcpl_ct_samples_grow(&in->pctf_samples);
281233611Sfabient			in->pctf_samples.sb[pmcin] += v;
282203790Sfabient			return;
283203790Sfabient		}
284203790Sfabient	}
285203790Sfabient
286203790Sfabient	pmcpl_ct_instr_grow(ct->pct_ninstr, &ct->pct_instr_c, &ct->pct_instr);
287203790Sfabient	in = &ct->pct_instr[ct->pct_ninstr];
288203790Sfabient	in->pctf_func = pc;
289203790Sfabient	pmcpl_ct_samples_init(&in->pctf_samples);
290203790Sfabient	pmcpl_ct_samples_grow(&in->pctf_samples);
291233611Sfabient	in->pctf_samples.sb[pmcin] = v;
292203790Sfabient	ct->pct_ninstr++;
293203790Sfabient}
294203790Sfabient
295203790Sfabient/*
296203790Sfabient * Allocate a new node.
297203790Sfabient */
298203790Sfabient
299203790Sfabientstatic struct pmcpl_ct_node *
300233611Sfabientpmcpl_ct_node_allocate(void)
301203790Sfabient{
302203790Sfabient	struct pmcpl_ct_node *ct;
303203790Sfabient
304203790Sfabient	if ((ct = malloc(sizeof(*ct))) == NULL)
305203790Sfabient		err(EX_OSERR, "ERROR: Cannot allocate callgraph node");
306203790Sfabient
307203790Sfabient	pmcpl_ct_samples_init(&ct->pct_samples);
308203790Sfabient
309233611Sfabient	ct->pct_sym	= NULL;
310233611Sfabient	ct->pct_image	= NULL;
311233611Sfabient	ct->pct_func	= 0;
312233611Sfabient
313203790Sfabient	ct->pct_narc	= 0;
314203790Sfabient	ct->pct_arc_c	= 0;
315203790Sfabient	ct->pct_arc	= NULL;
316203790Sfabient
317203790Sfabient	ct->pct_ninstr	= 0;
318203790Sfabient	ct->pct_instr_c	= 0;
319203790Sfabient	ct->pct_instr	= NULL;
320203790Sfabient
321233611Sfabient	ct->pct_color   = PMCPL_PCT_WHITE;
322233611Sfabient
323203790Sfabient	return (ct);
324203790Sfabient}
325203790Sfabient
326203790Sfabient/*
327203790Sfabient * Free a node.
328203790Sfabient */
329203790Sfabient
330203790Sfabientstatic void
331203790Sfabientpmcpl_ct_node_free(struct pmcpl_ct_node *ct)
332203790Sfabient{
333203790Sfabient	int i;
334203790Sfabient
335203790Sfabient	for (i = 0; i < ct->pct_narc; i++) {
336203790Sfabient		pmcpl_ct_samples_free(&ct->pct_arc[i].pcta_samples);
337203790Sfabient		pmcpl_ct_samples_free(&ct->pct_arc[i].pcta_callid);
338203790Sfabient	}
339203790Sfabient
340203790Sfabient	pmcpl_ct_samples_free(&ct->pct_samples);
341203790Sfabient	free(ct->pct_arc);
342203790Sfabient	free(ct->pct_instr);
343203790Sfabient	free(ct);
344203790Sfabient}
345203790Sfabient
346203790Sfabient/*
347203790Sfabient * Clear the graph tag on each node.
348203790Sfabient */
349203790Sfabientstatic void
350203790Sfabientpmcpl_ct_node_cleartag(void)
351203790Sfabient{
352203790Sfabient	int i;
353203790Sfabient	struct pmcpl_ct_node_hash *pch;
354203790Sfabient
355203790Sfabient	for (i = 0; i < PMCSTAT_NHASH; i++)
356233611Sfabient		STAILQ_FOREACH(pch, &pmcpl_ct_node_hash[i], pch_next)
357233611Sfabient			pch->pch_ctnode->pct_color = PMCPL_PCT_WHITE;
358203790Sfabient
359233611Sfabient	pmcpl_ct_root->pct_color = PMCPL_PCT_WHITE;
360203790Sfabient}
361203790Sfabient
362203790Sfabient/*
363203790Sfabient * Print the callchain line by line with maximum cost at top.
364203790Sfabient */
365203790Sfabient
366203790Sfabientstatic int
367203790Sfabientpmcpl_ct_node_dumptop(int pmcin, struct pmcpl_ct_node *ct,
368207755Sfabient    struct pmcpl_ct_sample *rsamples, int x, int *y)
369203790Sfabient{
370207755Sfabient	int i, terminal;
371210766Sfabient	struct pmcpl_ct_arc *arc;
372203790Sfabient
373233611Sfabient	if (ct->pct_color == PMCPL_PCT_GREY)
374203790Sfabient		return 0;
375203790Sfabient
376203790Sfabient	if (x >= PMCPL_CT_MAXCOL) {
377203790Sfabient		pmcpl_ct_topscreen[x][*y] = NULL;
378203790Sfabient		return 1;
379203790Sfabient	}
380203790Sfabient	pmcpl_ct_topscreen[x][*y] = ct;
381203790Sfabient
382203790Sfabient	/*
383207755Sfabient	 * Check if this is a terminal node.
384207755Sfabient	 * We need to check that some samples exist
385207755Sfabient	 * for at least one arc for that PMC.
386203790Sfabient	 */
387207755Sfabient	terminal = 1;
388210766Sfabient	for (i = 0; i < ct->pct_narc; i++) {
389210766Sfabient		arc = &ct->pct_arc[i];
390233611Sfabient		if (arc->pcta_child->pct_color != PMCPL_PCT_GREY &&
391233611Sfabient		    PMCPL_CT_SAMPLE(pmcin,
392210766Sfabient		    &arc->pcta_samples) != 0 &&
393210766Sfabient		    PMCPL_CT_SAMPLEP(pmcin,
394233611Sfabient		    &arc->pcta_samples) > pmcstat_threshold) {
395207755Sfabient			terminal = 0;
396207755Sfabient			break;
397207755Sfabient		}
398210766Sfabient	}
399207755Sfabient
400207755Sfabient	if (ct->pct_narc == 0 || terminal) {
401203790Sfabient		pmcpl_ct_topscreen[x+1][*y] = NULL;
402207755Sfabient		if (*y >= PMCPL_CT_MAXLINE)
403203790Sfabient			return 1;
404203790Sfabient		*y = *y + 1;
405203790Sfabient		for (i=0; i < x; i++)
406203790Sfabient			pmcpl_ct_topscreen[i][*y] =
407203790Sfabient			    pmcpl_ct_topscreen[i][*y - 1];
408203790Sfabient		return 0;
409203790Sfabient	}
410203790Sfabient
411233611Sfabient	ct->pct_color = PMCPL_PCT_GREY;
412203790Sfabient	for (i = 0; i < ct->pct_narc; i++) {
413206090Sfabient		if (PMCPL_CT_SAMPLE(pmcin,
414206090Sfabient		    &ct->pct_arc[i].pcta_samples) == 0)
415206090Sfabient			continue;
416203790Sfabient		if (PMCPL_CT_SAMPLEP(pmcin,
417203790Sfabient		    &ct->pct_arc[i].pcta_samples) > pmcstat_threshold) {
418203790Sfabient			if (pmcpl_ct_node_dumptop(pmcin,
419203790Sfabient			        ct->pct_arc[i].pcta_child,
420233611Sfabient			        rsamples, x+1, y)) {
421233611Sfabient				ct->pct_color = PMCPL_PCT_BLACK;
422203790Sfabient				return 1;
423233611Sfabient			}
424203790Sfabient		}
425203790Sfabient	}
426233611Sfabient	ct->pct_color = PMCPL_PCT_BLACK;
427203790Sfabient
428203790Sfabient	return 0;
429203790Sfabient}
430203790Sfabient
431203790Sfabient/*
432207755Sfabient * Compare two top line by sum.
433207755Sfabient */
434207755Sfabientstatic int
435207755Sfabientpmcpl_ct_line_compare(const void *a, const void *b)
436207755Sfabient{
437207755Sfabient	const struct pmcpl_ct_line *ct1, *ct2;
438207755Sfabient
439207755Sfabient	ct1 = (const struct pmcpl_ct_line *) a;
440207755Sfabient	ct2 = (const struct pmcpl_ct_line *) b;
441207755Sfabient
442207755Sfabient	/* Sort in reverse order */
443207755Sfabient	if (ct1->ln_sum < ct2->ln_sum)
444207755Sfabient		return (1);
445207755Sfabient	if (ct1->ln_sum > ct2->ln_sum)
446207755Sfabient		return (-1);
447207755Sfabient	return (0);
448207755Sfabient}
449207755Sfabient
450207755Sfabient/*
451203790Sfabient * Format and display given PMC index.
452203790Sfabient */
453203790Sfabient
454203790Sfabientstatic void
455203790Sfabientpmcpl_ct_node_printtop(struct pmcpl_ct_sample *rsamples, int pmcin, int maxy)
456203790Sfabient{
457207755Sfabient#undef	TS
458207755Sfabient#undef	TSI
459207755Sfabient#define	TS(x, y)	(pmcpl_ct_topscreen[x][y])
460207755Sfabient#define	TSI(x, y)	(pmcpl_ct_topscreen[x][pmcpl_ct_topmax[y].ln_index])
461207755Sfabient
462203790Sfabient	int v_attrs, ns_len, vs_len, is_len, width, indentwidth, x, y;
463203790Sfabient	float v;
464203790Sfabient	char ns[30], vs[10], is[20];
465203790Sfabient	struct pmcpl_ct_node *ct;
466203790Sfabient	const char *space = " ";
467203790Sfabient
468207755Sfabient	/*
469207755Sfabient	 * Sort by line cost.
470207755Sfabient	 */
471207755Sfabient	for (y = 0; ; y++) {
472207755Sfabient		ct = TS(1, y);
473207755Sfabient		if (ct == NULL)
474207755Sfabient			break;
475207755Sfabient
476207755Sfabient		pmcpl_ct_topmax[y].ln_sum = 0;
477207755Sfabient		pmcpl_ct_topmax[y].ln_index = y;
478207755Sfabient		for (x = 1; TS(x, y) != NULL; x++) {
479207755Sfabient			pmcpl_ct_topmax[y].ln_sum +=
480207755Sfabient			    PMCPL_CT_SAMPLE(pmcin, &TS(x, y)->pct_samples);
481207755Sfabient		}
482207755Sfabient	}
483207755Sfabient	qsort(pmcpl_ct_topmax, y, sizeof(pmcpl_ct_topmax[0]),
484207755Sfabient	    pmcpl_ct_line_compare);
485207755Sfabient	pmcpl_ct_topmax[y].ln_index = y;
486207755Sfabient
487203790Sfabient	for (y = 0; y < maxy; y++) {
488207755Sfabient		ct = TSI(1, y);
489207755Sfabient		if (ct == NULL)
490207755Sfabient			break;
491203790Sfabient
492207755Sfabient		if (y > 0)
493207755Sfabient			PMCSTAT_PRINTW("\n");
494203790Sfabient
495207755Sfabient		/* Output sum. */
496207755Sfabient		v = pmcpl_ct_topmax[y].ln_sum * 100.0 /
497207755Sfabient		    rsamples->sb[pmcin];
498207755Sfabient		snprintf(vs, sizeof(vs), "%.1f", v);
499207755Sfabient		v_attrs = PMCSTAT_ATTRPERCENT(v);
500207755Sfabient		PMCSTAT_ATTRON(v_attrs);
501207755Sfabient		PMCSTAT_PRINTW("%5.5s ", vs);
502207755Sfabient		PMCSTAT_ATTROFF(v_attrs);
503203790Sfabient
504207755Sfabient		width = indentwidth = 5 + 1;
505207755Sfabient
506207755Sfabient		for (x = 1; (ct = TSI(x, y)) != NULL; x++) {
507207755Sfabient
508203790Sfabient			vs[0] = '\0'; vs_len = 0;
509203790Sfabient			is[0] = '\0'; is_len = 0;
510203790Sfabient
511203790Sfabient			/* Format value. */
512203790Sfabient			v = PMCPL_CT_SAMPLEP(pmcin, &ct->pct_samples);
513203790Sfabient			if (v > pmcstat_threshold)
514207755Sfabient				vs_len  = snprintf(vs, sizeof(vs),
515207755Sfabient				    "(%.1f%%)", v);
516203790Sfabient			v_attrs = PMCSTAT_ATTRPERCENT(v);
517203790Sfabient
518203790Sfabient			if (pmcstat_skiplink && v <= pmcstat_threshold) {
519207755Sfabient				strlcpy(ns, ".", sizeof(ns));
520207755Sfabient				ns_len = 1;
521207755Sfabient			} else {
522233611Sfabient			if (ct->pct_sym != NULL) {
523203790Sfabient				ns_len = snprintf(ns, sizeof(ns), "%s",
524233611Sfabient				    pmcstat_string_unintern(ct->pct_sym->ps_name));
525203790Sfabient			} else
526203790Sfabient				ns_len = snprintf(ns, sizeof(ns), "%p",
527203790Sfabient				    (void *)ct->pct_func);
528203790Sfabient
529203790Sfabient			/* Format image. */
530207755Sfabient			if (x == 1 ||
531207755Sfabient			    TSI(x-1, y)->pct_image != ct->pct_image)
532203790Sfabient				is_len = snprintf(is, sizeof(is), "@%s",
533203790Sfabient				    pmcstat_string_unintern(ct->pct_image->pi_name));
534203790Sfabient
535203790Sfabient			/* Check for line wrap. */
536203790Sfabient			width += ns_len + is_len + vs_len + 1;
537207755Sfabient			}
538203790Sfabient			if (width >= pmcstat_displaywidth) {
539205693Sfabient				maxy--;
540205693Sfabient				if (y >= maxy)
541205693Sfabient					break;
542203790Sfabient				PMCSTAT_PRINTW("\n%*s", indentwidth, space);
543203790Sfabient				width = indentwidth + ns_len + is_len + vs_len;
544203790Sfabient			}
545203790Sfabient
546203790Sfabient			PMCSTAT_ATTRON(v_attrs);
547203790Sfabient			PMCSTAT_PRINTW("%s%s%s ", ns, is, vs);
548203790Sfabient			PMCSTAT_ATTROFF(v_attrs);
549203790Sfabient		}
550203790Sfabient	}
551203790Sfabient}
552203790Sfabient
553203790Sfabient/*
554203790Sfabient * Output top mode snapshot.
555203790Sfabient */
556203790Sfabient
557203790Sfabientvoid
558203790Sfabientpmcpl_ct_topdisplay(void)
559203790Sfabient{
560207755Sfabient	int y;
561206994Sfabient	struct pmcpl_ct_sample r, *rsamples;
562203790Sfabient
563206994Sfabient	rsamples = &r;
564206994Sfabient	pmcpl_ct_samples_root(rsamples);
565207755Sfabient	pmcpl_ct_node_cleartag();
566203790Sfabient
567207755Sfabient	PMCSTAT_PRINTW("%5.5s %s\n", "%SAMP", "CALLTREE");
568203790Sfabient
569207755Sfabient	y = 0;
570207755Sfabient	if (pmcpl_ct_node_dumptop(pmcstat_pmcinfilter,
571207755Sfabient	    pmcpl_ct_root, rsamples, 0, &y))
572207755Sfabient		PMCSTAT_PRINTW("...\n");
573207755Sfabient	pmcpl_ct_topscreen[1][y] = NULL;
574203790Sfabient
575207755Sfabient	pmcpl_ct_node_printtop(rsamples,
576207755Sfabient	    pmcstat_pmcinfilter, pmcstat_displayheight - 2);
577203790Sfabient
578206994Sfabient	pmcpl_ct_samples_free(rsamples);
579203790Sfabient}
580203790Sfabient
581203790Sfabient/*
582203790Sfabient * Handle top mode keypress.
583203790Sfabient */
584203790Sfabient
585203790Sfabientint
586203790Sfabientpmcpl_ct_topkeypress(int c, WINDOW *w)
587203790Sfabient{
588203790Sfabient
589203790Sfabient	switch (c) {
590203790Sfabient	case 'f':
591203790Sfabient		pmcstat_skiplink = !pmcstat_skiplink;
592227524Sobrien		wprintw(w, "skip empty link %s",
593227524Sobrien		    pmcstat_skiplink ? "on" : "off");
594203790Sfabient		break;
595203790Sfabient	}
596203790Sfabient
597203790Sfabient	return 0;
598203790Sfabient}
599203790Sfabient
600203790Sfabient/*
601203790Sfabient * Look for a callgraph node associated with pmc `pmcid' in the global
602203790Sfabient * hash table that corresponds to the given `pc' value in the process map
603203790Sfabient * `ppm'.
604203790Sfabient */
605203790Sfabient
606233611Sfabientstatic void
607233611Sfabientpmcpl_ct_node_update(struct pmcpl_ct_node *parent,
608233611Sfabient    struct pmcpl_ct_node *child, int pmcin, unsigned v, int cd)
609203790Sfabient{
610203790Sfabient	struct pmcpl_ct_arc *arc;
611203790Sfabient	int i;
612203790Sfabient
613203790Sfabient	assert(parent != NULL);
614203790Sfabient
615233611Sfabient	/*
616233611Sfabient	 * Find related arc in parent node and
617233611Sfabient	 * increment the sample count.
618233611Sfabient	 */
619233611Sfabient	for (i = 0; i < parent->pct_narc; i++) {
620233611Sfabient		if (parent->pct_arc[i].pcta_child == child) {
621233611Sfabient			arc = &parent->pct_arc[i];
622233611Sfabient			pmcpl_ct_samples_grow(&arc->pcta_samples);
623233611Sfabient			arc->pcta_samples.sb[pmcin] += v;
624233611Sfabient			/* Estimate call count. */
625233611Sfabient			if (cd) {
626233611Sfabient			pmcpl_ct_samples_grow(&arc->pcta_callid);
627233611Sfabient			if (pmcpl_ct_callid.sb[pmcin] -
628233611Sfabient			    arc->pcta_callid.sb[pmcin] > 1)
629233611Sfabient				arc->pcta_call++;
630233611Sfabient			arc->pcta_callid.sb[pmcin] =
631233611Sfabient			    pmcpl_ct_callid.sb[pmcin];
632233611Sfabient			}
633233611Sfabient			return;
634233611Sfabient		}
635233611Sfabient	}
636203790Sfabient
637203790Sfabient	/*
638233611Sfabient	 * No arc found for us, add ourself to the parent.
639203790Sfabient	 */
640233611Sfabient	pmcpl_ct_arc_grow(parent->pct_narc,
641233611Sfabient	    &parent->pct_arc_c, &parent->pct_arc);
642233611Sfabient	arc = &parent->pct_arc[parent->pct_narc];
643233611Sfabient	pmcpl_ct_samples_grow(&arc->pcta_samples);
644233611Sfabient	arc->pcta_samples.sb[pmcin] = v;
645233611Sfabient	arc->pcta_call = 1;
646233611Sfabient	if (cd) {
647233611Sfabient		pmcpl_ct_samples_grow(&arc->pcta_callid);
648233611Sfabient		arc->pcta_callid.sb[pmcin] = pmcpl_ct_callid.sb[pmcin];
649233611Sfabient	}
650233611Sfabient	arc->pcta_child = child;
651233611Sfabient	parent->pct_narc++;
652233611Sfabient}
653203790Sfabient
654233611Sfabient/*
655233611Sfabient * Lookup by image/pc.
656233611Sfabient */
657233611Sfabient
658233611Sfabientstatic struct pmcpl_ct_node *
659233611Sfabientpmcpl_ct_node_hash_lookup(struct pmcstat_image *image, uintfptr_t pc,
660233611Sfabient    struct pmcstat_symbol *sym, char *fl, char *fn)
661233611Sfabient{
662233611Sfabient	int i;
663233611Sfabient	unsigned int hash;
664233611Sfabient	struct pmcpl_ct_node *ct;
665233611Sfabient	struct pmcpl_ct_node_hash *h;
666233611Sfabient	pmcstat_interned_string	ifl, ifn;
667233611Sfabient
668233611Sfabient	if (fn != NULL) {
669233611Sfabient		ifl = pmcstat_string_intern(fl);
670233611Sfabient		ifn = pmcstat_string_intern(fn);
671233611Sfabient	} else {
672233611Sfabient		ifl = 0;
673233611Sfabient		ifn = 0;
674233611Sfabient	}
675233611Sfabient
676203790Sfabient	for (hash = i = 0; i < (int)sizeof(uintfptr_t); i++)
677203790Sfabient		hash += (pc >> i) & 0xFF;
678203790Sfabient
679203790Sfabient	hash &= PMCSTAT_HASH_MASK;
680203790Sfabient
681233611Sfabient	STAILQ_FOREACH(h, &pmcpl_ct_node_hash[hash], pch_next) {
682203790Sfabient		ct = h->pch_ctnode;
683203790Sfabient
684203790Sfabient		assert(ct != NULL);
685203790Sfabient
686203790Sfabient		if (ct->pct_image == image && ct->pct_func == pc) {
687233611Sfabient			if (fn == NULL)
688233611Sfabient				return (ct);
689233611Sfabient			if (ct->pct_type == PMCPL_PCT_NAME &&
690233611Sfabient			    ct->pct_ifl == ifl && ct->pct_ifn == ifn)
691233611Sfabient				return (ct);
692203790Sfabient		}
693203790Sfabient	}
694203790Sfabient
695203790Sfabient	/*
696203790Sfabient	 * We haven't seen this (pmcid, pc) tuple yet, so allocate a
697203790Sfabient	 * new callgraph node and a new hash table entry for it.
698203790Sfabient	 */
699233611Sfabient	ct = pmcpl_ct_node_allocate();
700203790Sfabient	if ((h = malloc(sizeof(*h))) == NULL)
701203790Sfabient		err(EX_OSERR, "ERROR: Could not allocate callgraph node");
702203790Sfabient
703233611Sfabient	if (fn != NULL) {
704233611Sfabient		ct->pct_type = PMCPL_PCT_NAME;
705233611Sfabient		ct->pct_ifl = ifl;
706233611Sfabient		ct->pct_ifn = ifn;
707233611Sfabient	} else
708233611Sfabient		ct->pct_type = PMCPL_PCT_ADDR;
709233611Sfabient	ct->pct_image = image;
710233611Sfabient	ct->pct_func = pc;
711233611Sfabient	ct->pct_sym = sym;
712233611Sfabient
713203790Sfabient	h->pch_ctnode = ct;
714233611Sfabient	STAILQ_INSERT_HEAD(&pmcpl_ct_node_hash[hash], h, pch_next);
715203790Sfabient	return (ct);
716203790Sfabient}
717203790Sfabient
718203790Sfabient/*
719203790Sfabient * Record a callchain.
720203790Sfabient */
721203790Sfabient
722203790Sfabientvoid
723203790Sfabientpmcpl_ct_process(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr,
724203790Sfabient    uint32_t nsamples, uintfptr_t *cc, int usermode, uint32_t cpu)
725203790Sfabient{
726233611Sfabient	int i, n, pmcin;
727233611Sfabient	uintfptr_t pc, loadaddress;
728233611Sfabient	struct pmcstat_image *image;
729233611Sfabient	struct pmcstat_symbol *sym;
730203790Sfabient	struct pmcstat_pcmap *ppm[PMC_CALLCHAIN_DEPTH_MAX];
731203790Sfabient	struct pmcstat_process *km;
732233611Sfabient	struct pmcpl_ct_node *ct;
733233611Sfabient	struct pmcpl_ct_node *ctl[PMC_CALLCHAIN_DEPTH_MAX+1];
734203790Sfabient
735203790Sfabient	(void) cpu;
736203790Sfabient
737203790Sfabient	assert(nsamples>0 && nsamples<=PMC_CALLCHAIN_DEPTH_MAX);
738203790Sfabient
739203790Sfabient	/* Get the PMC index. */
740203790Sfabient	pmcin = pmcr->pr_pmcin;
741203790Sfabient
742203790Sfabient	/*
743203790Sfabient	 * Validate mapping for the callchain.
744203790Sfabient	 * Go from bottom to first invalid entry.
745203790Sfabient	 */
746203790Sfabient	km = pmcstat_kernproc;
747203790Sfabient	for (n = 0; n < (int)nsamples; n++) {
748203790Sfabient		ppm[n] = pmcstat_process_find_map(usermode ?
749203790Sfabient		    pp : km, cc[n]);
750203790Sfabient		if (ppm[n] == NULL) {
751203790Sfabient			/* Detect full frame capture (kernel + user). */
752203790Sfabient			if (!usermode) {
753203790Sfabient				ppm[n] = pmcstat_process_find_map(pp, cc[n]);
754203790Sfabient				if (ppm[n] != NULL)
755203790Sfabient					km = pp;
756203790Sfabient			}
757203790Sfabient		}
758203790Sfabient		if (ppm[n] == NULL)
759203790Sfabient			break;
760203790Sfabient	}
761203790Sfabient	if (n-- == 0) {
762203790Sfabient		pmcstat_stats.ps_callchain_dubious_frames++;
763206090Sfabient		pmcr->pr_dubious_frames++;
764203790Sfabient		return;
765203790Sfabient	}
766203790Sfabient
767203790Sfabient	/* Increase the call generation counter. */
768203790Sfabient	pmcpl_ct_samples_grow(&pmcpl_ct_callid);
769203790Sfabient	pmcpl_ct_callid.sb[pmcin]++;
770203790Sfabient
771203790Sfabient	/*
772233611Sfabient	 * Build node list.
773203790Sfabient	 */
774233611Sfabient	ctl[0] = pmcpl_ct_root;
775233611Sfabient	for (i = 1; n >= 0; n--) {
776233611Sfabient		image = ppm[n]->ppm_image;
777233611Sfabient		loadaddress = ppm[n]->ppm_lowpc +
778233611Sfabient		    image->pi_vaddr - image->pi_start;
779233611Sfabient		/* Convert to an offset in the image. */
780233611Sfabient		pc = cc[n] - loadaddress;
781233611Sfabient		/*
782233611Sfabient		 * Try determine the function at this offset.  If we can't
783233611Sfabient		 * find a function round leave the `pc' value alone.
784233611Sfabient		 */
785233611Sfabient		if ((sym = pmcstat_symbol_search(image, pc)) != NULL)
786233611Sfabient			pc = sym->ps_start;
787233611Sfabient		else
788233611Sfabient			pmcstat_stats.ps_samples_unknown_function++;
789233611Sfabient
790233611Sfabient		ct = pmcpl_ct_node_hash_lookup(image, pc, sym, NULL, NULL);
791233611Sfabient		if (ct == NULL) {
792203790Sfabient			pmcstat_stats.ps_callchain_dubious_frames++;
793203790Sfabient			continue;
794203790Sfabient		}
795233611Sfabient		ctl[i++] = ct;
796203790Sfabient	}
797233611Sfabient	/* No valid node found. */
798233611Sfabient	if (i == 1)
799233611Sfabient		return;
800233611Sfabient	n = i;
801203790Sfabient
802233611Sfabient	ct = ctl[0];
803233611Sfabient	for (i = 1; i < n; i++)
804233611Sfabient		pmcpl_ct_node_update(ctl[i-1], ctl[i], pmcin, 1, 1);
805233611Sfabient
806203790Sfabient	/*
807203790Sfabient	 * Increment the sample count for this PMC.
808203790Sfabient	 */
809233611Sfabient	pmcpl_ct_samples_grow(&ctl[n-1]->pct_samples);
810233611Sfabient	ctl[n-1]->pct_samples.sb[pmcin]++;
811203790Sfabient
812233611Sfabient	/* Update per instruction sample if required. */
813233611Sfabient	if (args.pa_ctdumpinstr)
814233611Sfabient		pmcpl_ct_instr_add(ctl[n-1], pmcin, cc[0] -
815233611Sfabient		    (ppm[0]->ppm_lowpc + ppm[0]->ppm_image->pi_vaddr -
816233611Sfabient		     ppm[0]->ppm_image->pi_start), 1);
817233611Sfabient}
818233611Sfabient
819233611Sfabient/*
820233611Sfabient * Print node child cost.
821233611Sfabient */
822233611Sfabient
823233611Sfabientstatic void
824233611Sfabientpmcpl_ct_node_printchild(struct pmcpl_ct_node *ct, uintfptr_t paddr,
825233611Sfabient    int pline)
826233611Sfabient{
827233611Sfabient	int i, j, line;
828233611Sfabient	uintfptr_t addr;
829233611Sfabient	struct pmcpl_ct_node *child;
830233611Sfabient	char sourcefile[PATH_MAX];
831233611Sfabient	char funcname[PATH_MAX];
832233611Sfabient
833233611Sfabient	/*
834233611Sfabient	 * Child cost.
835298885Spfg	 * TODO: attach child cost to the real position in the function.
836233611Sfabient	 * TODO: cfn=<fn> / call <ncall> addr(<fn>) / addr(call <fn>) <arccost>
837233611Sfabient	 */
838233611Sfabient	for (i=0 ; i<ct->pct_narc; i++) {
839233611Sfabient		child = ct->pct_arc[i].pcta_child;
840233611Sfabient		/* Object binary. */
841233611Sfabient		fprintf(args.pa_graphfile, "cob=%s\n",
842233611Sfabient		    pmcstat_string_unintern(child->pct_image->pi_fullpath));
843233611Sfabient		/* Child function name. */
844233611Sfabient		addr = child->pct_image->pi_vaddr + child->pct_func;
845233611Sfabient		line = 0;
846233611Sfabient		/* Child function source file. */
847233611Sfabient		if (child->pct_type == PMCPL_PCT_NAME) {
848233611Sfabient			fprintf(args.pa_graphfile, "cfi=%s\ncfn=%s\n",
849233611Sfabient			    pmcstat_string_unintern(child->pct_ifl),
850233611Sfabient			    pmcstat_string_unintern(child->pct_ifn));
851233611Sfabient		} else if (pmcstat_image_addr2line(child->pct_image, addr,
852233611Sfabient		    sourcefile, sizeof(sourcefile), &line,
853233611Sfabient		    funcname, sizeof(funcname))) {
854233611Sfabient			fprintf(args.pa_graphfile, "cfi=%s\ncfn=%s\n",
855233611Sfabient				sourcefile, funcname);
856233611Sfabient		} else {
857233611Sfabient			if (child->pct_sym != NULL)
858233611Sfabient				fprintf(args.pa_graphfile,
859233611Sfabient				    "cfi=???\ncfn=%s\n",
860233611Sfabient				    pmcstat_string_unintern(
861233611Sfabient				        child->pct_sym->ps_name));
862233611Sfabient			else
863233611Sfabient				fprintf(args.pa_graphfile,
864233611Sfabient				    "cfi=???\ncfn=%p\n", (void *)addr);
865233611Sfabient		}
866233611Sfabient
867233611Sfabient		/* Child function address, line and call count. */
868233611Sfabient		fprintf(args.pa_graphfile, "calls=%u %p %u\n",
869233611Sfabient		    ct->pct_arc[i].pcta_call, (void *)addr, line);
870233611Sfabient
871233611Sfabient		/*
872233611Sfabient		 * Call address, line, sample.
873233611Sfabient		 * TODO: Associate call address to the right location.
874233611Sfabient		 */
875233611Sfabient		fprintf(args.pa_graphfile, "%p %u", (void *)paddr, pline);
876233611Sfabient		for (j = 0; j<pmcstat_npmcs; j++)
877233611Sfabient			fprintf(args.pa_graphfile, " %u",
878233611Sfabient			    PMCPL_CT_SAMPLE(j, &ct->pct_arc[i].pcta_samples));
879233611Sfabient		fprintf(args.pa_graphfile, "\n");
880203790Sfabient	}
881203790Sfabient}
882203790Sfabient
883203790Sfabient/*
884203790Sfabient * Print node self cost.
885203790Sfabient */
886203790Sfabient
887203790Sfabientstatic void
888203790Sfabientpmcpl_ct_node_printself(struct pmcpl_ct_node *ct)
889203790Sfabient{
890233611Sfabient	int i, j, fline, line;
891233611Sfabient	uintfptr_t faddr, addr;
892203790Sfabient	char sourcefile[PATH_MAX];
893203790Sfabient	char funcname[PATH_MAX];
894203790Sfabient
895203790Sfabient	/*
896203790Sfabient	 * Object binary.
897203790Sfabient	 */
898233611Sfabient	fprintf(args.pa_graphfile, "ob=%s\n",
899233611Sfabient	    pmcstat_string_unintern(ct->pct_image->pi_fullpath));
900203790Sfabient
901203790Sfabient	/*
902203790Sfabient	 * Function name.
903203790Sfabient	 */
904233611Sfabient	faddr = ct->pct_image->pi_vaddr + ct->pct_func;
905233611Sfabient	fline = 0;
906233611Sfabient	if (ct->pct_type == PMCPL_PCT_NAME) {
907233611Sfabient		fprintf(args.pa_graphfile, "fl=%s\nfn=%s\n",
908233611Sfabient		    pmcstat_string_unintern(ct->pct_ifl),
909233611Sfabient		    pmcstat_string_unintern(ct->pct_ifn));
910233611Sfabient	} else if (pmcstat_image_addr2line(ct->pct_image, faddr,
911233611Sfabient	    sourcefile, sizeof(sourcefile), &fline,
912203790Sfabient	    funcname, sizeof(funcname))) {
913233611Sfabient		fprintf(args.pa_graphfile, "fl=%s\nfn=%s\n",
914233611Sfabient		    sourcefile, funcname);
915203790Sfabient	} else {
916233611Sfabient		if (ct->pct_sym != NULL)
917233611Sfabient			fprintf(args.pa_graphfile, "fl=???\nfn=%s\n",
918233611Sfabient			    pmcstat_string_unintern(ct->pct_sym->ps_name));
919203790Sfabient		else
920233611Sfabient			fprintf(args.pa_graphfile, "fl=???\nfn=%p\n",
921203790Sfabient			    (void *)(ct->pct_image->pi_vaddr + ct->pct_func));
922203790Sfabient	}
923203790Sfabient
924203790Sfabient	/*
925203790Sfabient	 * Self cost.
926203790Sfabient	 */
927203790Sfabient	if (ct->pct_ninstr > 0) {
928233611Sfabient		/*
929233611Sfabient		 * Per location cost.
930233611Sfabient		 */
931203790Sfabient		for (i = 0; i < ct->pct_ninstr; i++) {
932203790Sfabient			addr = ct->pct_image->pi_vaddr +
933203790Sfabient			    ct->pct_instr[i].pctf_func;
934203790Sfabient			line = 0;
935233611Sfabient			pmcstat_image_addr2line(ct->pct_image, addr,
936203790Sfabient			    sourcefile, sizeof(sourcefile), &line,
937233611Sfabient			    funcname, sizeof(funcname));
938233611Sfabient			fprintf(args.pa_graphfile, "%p %u",
939233611Sfabient			    (void *)addr, line);
940203790Sfabient			for (j = 0; j<pmcstat_npmcs; j++)
941203790Sfabient				fprintf(args.pa_graphfile, " %u",
942203790Sfabient				    PMCPL_CT_SAMPLE(j,
943203790Sfabient				    &ct->pct_instr[i].pctf_samples));
944203790Sfabient			fprintf(args.pa_graphfile, "\n");
945203790Sfabient		}
946203790Sfabient	} else {
947233611Sfabient		/* Global cost function cost. */
948233611Sfabient		fprintf(args.pa_graphfile, "%p %u", (void *)faddr, fline);
949203790Sfabient		for (i = 0; i<pmcstat_npmcs ; i++)
950203790Sfabient			fprintf(args.pa_graphfile, " %u",
951203790Sfabient			    PMCPL_CT_SAMPLE(i, &ct->pct_samples));
952203790Sfabient		fprintf(args.pa_graphfile, "\n");
953203790Sfabient	}
954233611Sfabient
955233611Sfabient	pmcpl_ct_node_printchild(ct, faddr, fline);
956203790Sfabient}
957203790Sfabient
958233611Sfabientstatic void
959233611Sfabientpmcpl_ct_printnode(struct pmcpl_ct_node *ct)
960233611Sfabient{
961233611Sfabient	int i;
962233611Sfabient
963233611Sfabient	if (ct == pmcpl_ct_root) {
964233611Sfabient		fprintf(args.pa_graphfile, "fn=root\n");
965233611Sfabient		fprintf(args.pa_graphfile, "0x0 1");
966233611Sfabient		for (i = 0; i<pmcstat_npmcs ; i++)
967233611Sfabient			fprintf(args.pa_graphfile, " 0");
968233611Sfabient		fprintf(args.pa_graphfile, "\n");
969233611Sfabient		pmcpl_ct_node_printchild(ct, 0, 0);
970233611Sfabient	} else
971233611Sfabient		pmcpl_ct_node_printself(ct);
972233611Sfabient}
973233611Sfabient
974203790Sfabient/*
975233611Sfabient * Breadth first traversal.
976203790Sfabient */
977203790Sfabient
978203790Sfabientstatic void
979233611Sfabientpmcpl_ct_bfs(struct pmcpl_ct_node *ct)
980203790Sfabient{
981233611Sfabient	int i;
982233611Sfabient	struct pmcpl_ct_node_hash *pch, *pchc;
983203790Sfabient	struct pmcpl_ct_node *child;
984233611Sfabient	STAILQ_HEAD(,pmcpl_ct_node_hash) q;
985233611Sfabient
986233611Sfabient	STAILQ_INIT(&q);
987233611Sfabient	if ((pch = malloc(sizeof(*pch))) == NULL)
988233611Sfabient		err(EX_OSERR, "ERROR: Cannot allocate queue");
989233611Sfabient	pch->pch_ctnode = ct;
990233611Sfabient	STAILQ_INSERT_TAIL(&q, pch, pch_next);
991233611Sfabient	ct->pct_color = PMCPL_PCT_BLACK;
992233611Sfabient
993233611Sfabient	while (!STAILQ_EMPTY(&q)) {
994233611Sfabient		pch = STAILQ_FIRST(&q);
995233611Sfabient		STAILQ_REMOVE_HEAD(&q, pch_next);
996233611Sfabient		pmcpl_ct_printnode(pch->pch_ctnode);
997233611Sfabient		for (i = 0; i<pch->pch_ctnode->pct_narc; i++) {
998233611Sfabient			child = pch->pch_ctnode->pct_arc[i].pcta_child;
999233611Sfabient			if (child->pct_color == PMCPL_PCT_WHITE) {
1000233611Sfabient				child->pct_color = PMCPL_PCT_BLACK;
1001233611Sfabient				if ((pchc = malloc(sizeof(*pchc))) == NULL)
1002233611Sfabient					err(EX_OSERR,
1003233611Sfabient					    "ERROR: Cannot allocate queue");
1004233611Sfabient				pchc->pch_ctnode = child;
1005233611Sfabient				STAILQ_INSERT_TAIL(&q, pchc, pch_next);
1006233611Sfabient			}
1007233611Sfabient		}
1008233611Sfabient		free(pch);
1009233611Sfabient	}
1010233611Sfabient}
1011233611Sfabient
1012233611Sfabient/*
1013233611Sfabient * Detect and fix inlined location.
1014233611Sfabient */
1015233611Sfabient
1016233611Sfabientstatic void
1017233611Sfabient_pmcpl_ct_expand_inline(struct pmcpl_ct_node *ct)
1018233611Sfabient{
1019233611Sfabient	int i, j;
1020233611Sfabient	unsigned fline, line, v;
1021233611Sfabient	uintfptr_t faddr, addr, pc;
1022203790Sfabient	char sourcefile[PATH_MAX];
1023233611Sfabient	char ffuncname[PATH_MAX], funcname[PATH_MAX];
1024233611Sfabient	char buffer[PATH_MAX];
1025233611Sfabient	struct pmcpl_ct_node *child;
1026203790Sfabient
1027203790Sfabient	/*
1028233611Sfabient	 * Resolve parent and compare to each instr location.
1029203790Sfabient	 */
1030233611Sfabient	faddr = ct->pct_image->pi_vaddr + ct->pct_func;
1031233611Sfabient	fline = 0;
1032233611Sfabient	if (!pmcstat_image_addr2line(ct->pct_image, faddr,
1033233611Sfabient	    sourcefile, sizeof(sourcefile), &fline,
1034233611Sfabient	    ffuncname, sizeof(ffuncname)))
1035233611Sfabient		return;
1036203790Sfabient
1037233611Sfabient	for (i = 0; i < ct->pct_ninstr; i++) {
1038233611Sfabient		addr = ct->pct_image->pi_vaddr +
1039233611Sfabient		    ct->pct_instr[i].pctf_func;
1040233611Sfabient		line = 0;
1041233611Sfabient		if (!pmcstat_image_addr2line(ct->pct_image, addr,
1042203790Sfabient		    sourcefile, sizeof(sourcefile), &line,
1043233611Sfabient		    funcname, sizeof(funcname)))
1044233611Sfabient			continue;
1045203790Sfabient
1046233611Sfabient		if (strcmp(funcname, ffuncname) == 0)
1047233611Sfabient			continue;
1048203790Sfabient
1049233611Sfabient		/*
1050233611Sfabient		 * - Lookup/create inline node by function name.
1051233611Sfabient		 * - Move instr PMCs to the inline node.
1052233611Sfabient		 * - Link nodes.
1053233611Sfabient		 * The lookup create a specific node per image/pc.
1054233611Sfabient		 */
1055233611Sfabient		if (args.pa_verbosity >= 2)
1056233611Sfabient			fprintf(args.pa_printfile,
1057233611Sfabient			    "WARNING: inlined function at %p %s in %s\n",
1058233611Sfabient			    (void *)addr, funcname, ffuncname);
1059233611Sfabient
1060233611Sfabient		snprintf(buffer, sizeof(buffer), "%s@%s",
1061233611Sfabient			funcname, ffuncname);
1062233611Sfabient		child = pmcpl_ct_node_hash_lookup(ct->pct_image,
1063233611Sfabient		    ct->pct_func, ct->pct_sym, sourcefile, buffer);
1064233611Sfabient		assert(child != NULL);
1065233611Sfabient		pc = ct->pct_instr[i].pctf_func;
1066233611Sfabient		for (j = 0; j<pmcstat_npmcs; j++) {
1067233611Sfabient			v = PMCPL_CT_SAMPLE(j,
1068233611Sfabient			    &ct->pct_instr[i].pctf_samples);
1069233611Sfabient			if (v == 0)
1070233611Sfabient				continue;
1071233611Sfabient			pmcpl_ct_instr_add(child, j, pc, v);
1072233611Sfabient			pmcpl_ct_node_update(ct, child, j, v, 0);
1073233611Sfabient			if (j < ct->pct_samples.npmcs)
1074233611Sfabient				ct->pct_samples.sb[j] -=
1075233611Sfabient				    ct->pct_instr[i].pctf_samples.sb[j];
1076233611Sfabient			ct->pct_instr[i].pctf_samples.sb[j] = 0;
1077203790Sfabient		}
1078203790Sfabient	}
1079203790Sfabient}
1080203790Sfabient
1081233611Sfabientstatic void
1082233611Sfabientpmcpl_ct_expand_inline(void)
1083233611Sfabient{
1084233611Sfabient	int i;
1085233611Sfabient	struct pmcpl_ct_node_hash *pch;
1086233611Sfabient
1087233611Sfabient	if (!args.pa_ctdumpinstr)
1088233611Sfabient		return;
1089233611Sfabient
1090233611Sfabient	for (i = 0; i < PMCSTAT_NHASH; i++)
1091233611Sfabient		STAILQ_FOREACH(pch, &pmcpl_ct_node_hash[i], pch_next)
1092233611Sfabient			if (pch->pch_ctnode->pct_type == PMCPL_PCT_ADDR)
1093233611Sfabient				_pmcpl_ct_expand_inline(pch->pch_ctnode);
1094233611Sfabient}
1095233611Sfabient
1096203790Sfabient/*
1097203790Sfabient * Clean the PMC name for Kcachegrind formula
1098203790Sfabient */
1099203790Sfabient
1100203790Sfabientstatic void
1101203790Sfabientpmcpl_ct_fixup_pmcname(char *s)
1102203790Sfabient{
1103203790Sfabient	char *p;
1104203790Sfabient
1105203790Sfabient	for (p = s; *p; p++)
1106203790Sfabient		if (!isalnum(*p))
1107203790Sfabient			*p = '_';
1108203790Sfabient}
1109203790Sfabient
1110203790Sfabient/*
1111203790Sfabient * Print a calltree (KCachegrind) for all PMCs.
1112203790Sfabient */
1113203790Sfabient
1114203790Sfabientstatic void
1115203790Sfabientpmcpl_ct_print(void)
1116203790Sfabient{
1117233611Sfabient	int i;
1118233611Sfabient	char name[40];
1119203790Sfabient	struct pmcpl_ct_sample rsamples;
1120203790Sfabient
1121203790Sfabient	pmcpl_ct_samples_root(&rsamples);
1122233611Sfabient	pmcpl_ct_expand_inline();
1123203790Sfabient
1124203790Sfabient	fprintf(args.pa_graphfile,
1125203790Sfabient		"version: 1\n"
1126203790Sfabient		"creator: pmcstat\n"
1127203790Sfabient		"positions: instr line\n"
1128203790Sfabient		"events:");
1129203790Sfabient	for (i=0; i<pmcstat_npmcs; i++) {
1130203790Sfabient		snprintf(name, sizeof(name), "%s_%d",
1131203790Sfabient		    pmcstat_pmcindex_to_name(i), i);
1132203790Sfabient		pmcpl_ct_fixup_pmcname(name);
1133203790Sfabient		fprintf(args.pa_graphfile, " %s", name);
1134203790Sfabient	}
1135203790Sfabient	fprintf(args.pa_graphfile, "\nsummary:");
1136203790Sfabient	for (i=0; i<pmcstat_npmcs ; i++)
1137203790Sfabient		fprintf(args.pa_graphfile, " %u",
1138203790Sfabient		    PMCPL_CT_SAMPLE(i, &rsamples));
1139203790Sfabient	fprintf(args.pa_graphfile, "\n");
1140233611Sfabient	pmcpl_ct_bfs(pmcpl_ct_root);
1141203790Sfabient	pmcpl_ct_samples_free(&rsamples);
1142203790Sfabient}
1143203790Sfabient
1144203790Sfabientint
1145203790Sfabientpmcpl_ct_configure(char *opt)
1146203790Sfabient{
1147203790Sfabient
1148203790Sfabient	if (strncmp(opt, "skiplink=", 9) == 0) {
1149203790Sfabient		pmcstat_skiplink = atoi(opt+9);
1150203790Sfabient	} else
1151203790Sfabient		return (0);
1152203790Sfabient
1153203790Sfabient	return (1);
1154203790Sfabient}
1155203790Sfabient
1156203790Sfabientint
1157203790Sfabientpmcpl_ct_init(void)
1158203790Sfabient{
1159203790Sfabient	int i;
1160203790Sfabient
1161233611Sfabient	pmcpl_ct_root = pmcpl_ct_node_allocate();
1162203790Sfabient
1163203790Sfabient	for (i = 0; i < PMCSTAT_NHASH; i++)
1164233611Sfabient		STAILQ_INIT(&pmcpl_ct_node_hash[i]);
1165203790Sfabient
1166203790Sfabient	pmcpl_ct_samples_init(&pmcpl_ct_callid);
1167203790Sfabient
1168203790Sfabient	return (0);
1169203790Sfabient}
1170203790Sfabient
1171203790Sfabientvoid
1172203790Sfabientpmcpl_ct_shutdown(FILE *mf)
1173203790Sfabient{
1174203790Sfabient	int i;
1175203790Sfabient	struct pmcpl_ct_node_hash *pch, *pchtmp;
1176203790Sfabient
1177203790Sfabient	(void) mf;
1178203790Sfabient
1179203790Sfabient	if (args.pa_flags & FLAG_DO_CALLGRAPHS)
1180203790Sfabient		pmcpl_ct_print();
1181203790Sfabient
1182203790Sfabient	/*
1183203790Sfabient	 * Free memory.
1184203790Sfabient	 */
1185203790Sfabient
1186203790Sfabient	for (i = 0; i < PMCSTAT_NHASH; i++) {
1187233611Sfabient		STAILQ_FOREACH_SAFE(pch, &pmcpl_ct_node_hash[i], pch_next,
1188203790Sfabient		    pchtmp) {
1189203790Sfabient			pmcpl_ct_node_free(pch->pch_ctnode);
1190203790Sfabient			free(pch);
1191203790Sfabient		}
1192203790Sfabient	}
1193203790Sfabient
1194203790Sfabient	pmcpl_ct_node_free(pmcpl_ct_root);
1195203790Sfabient	pmcpl_ct_root = NULL;
1196203790Sfabient
1197203790Sfabient	pmcpl_ct_samples_free(&pmcpl_ct_callid);
1198203790Sfabient}
1199203790Sfabient
1200