xref: /dragonfly/usr.bin/flame_graph/process.c (revision 8af44722)
1 /*
2  * Copyright (c) 2020 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "flame.h"
36 
37 typedef struct elm {
38 	struct elm *next;
39 	uint64_t	hv;
40 	long		ticks;
41 	const char	*id;
42 	size_t		idlen;
43 } elm_t;
44 
45 #define MAXELM	256
46 #define HSIZE	(1024*1024)
47 #define HMASK	(HSIZE - 1)
48 
49 static elm_t *elm_lookup(const char *s);
50 static void flame_process_dump(void);
51 
52 long total_ticks;
53 
54 void
55 flame_process_loop(void)
56 {
57 	char buf[4096];
58 	char *s;
59 	elm_t *elm;
60 	/*elm_t *elms[MAXELM];*/
61 	int n;
62 
63 	while (fgets(buf, sizeof(buf), stdin) != NULL) {
64 		n = 0;
65 
66 		s = strtok(buf, " \t\n\r");
67 		if (s == NULL || strchr(s, '/') == NULL)
68 			continue;
69 		while ((s = strtok(NULL, " \t\n\r")) != NULL) {
70 			elm = elm_lookup(s);
71 			/*elms[n] = elm;*/
72 			++elm->ticks;
73 
74 			if (n == MAXELM)
75 				break;
76 			++n;
77 		}
78 		++total_ticks;
79 		/* more processing later */
80 	}
81 	flame_process_dump();
82 }
83 
84 static elm_t *elm_hash_array[HSIZE];
85 
86 static elm_t *
87 elm_lookup(const char *s)
88 {
89 	size_t len;
90 	uint64_t hv;
91 	elm_t **scanp;
92 	elm_t *scan;
93 
94 	if (s[0] == '0' && s[1] == 'x') {
95 		hv = strtoul(s, NULL, 0);
96 		if (hv < 0x8000000000000000LU)
97 			s = "__userland__";
98 	}
99 
100 	hv = 0;
101 	for (len = 0; s[len] && s[len] != '+' && s[len] != '('; ++len)
102 		hv = hv * 13 ^ (uint8_t)s[len];
103 
104 	scanp = &elm_hash_array[hv % HSIZE];
105 	while ((scan = *scanp) != NULL) {
106 		if (scan->hv == hv && len == scan->idlen &&
107 		    bcmp(s, scan->id, len) == 0) {
108 			return scan;
109 		}
110 		scanp = &scan->next;
111 	}
112 	scan = malloc(sizeof(elm_t));
113 	bzero(scan, sizeof(*scan));
114 	*scanp = scan;
115 	scan->hv = hv;
116 	scan->id = strdup(s);
117 	scan->idlen = len;
118 
119 	return scan;
120 }
121 
122 static void
123 flame_process_dump(void)
124 {
125 	elm_t *elm;
126 	int i;
127 
128 	for (i = 0; i < HSIZE; ++i) {
129 		for (elm = elm_hash_array[i]; elm; elm = elm->next) {
130 			printf("%-6ld %6.3f%% %*.*s\n",
131 				elm->ticks,
132 				(double)elm->ticks * 100.0 /
133 				 (double)total_ticks,
134 				(int)elm->idlen, (int)elm->idlen, elm->id);
135 		}
136 	}
137 }
138