Commit | Line | Data |
---|---|---|
f9224c5c ACM |
1 | #define _GNU_SOURCE |
2 | #include <stdio.h> | |
3 | #undef _GNU_SOURCE | |
4 | ||
5 | #include <stdlib.h> | |
6 | #include <newt.h> | |
7081e087 | 7 | #include <sys/ttydefaults.h> |
f9224c5c ACM |
8 | |
9 | #include "cache.h" | |
10 | #include "hist.h" | |
11 | #include "session.h" | |
12 | #include "sort.h" | |
13 | #include "symbol.h" | |
14 | ||
7081e087 ACM |
15 | static void newt_form__set_exit_keys(newtComponent self) |
16 | { | |
17 | newtFormAddHotKey(self, NEWT_KEY_ESCAPE); | |
18 | newtFormAddHotKey(self, 'Q'); | |
19 | newtFormAddHotKey(self, 'q'); | |
20 | newtFormAddHotKey(self, CTRL('c')); | |
21 | } | |
22 | ||
23 | static newtComponent newt_form__new(void) | |
24 | { | |
25 | newtComponent self = newtForm(NULL, NULL, 0); | |
26 | if (self) | |
27 | newt_form__set_exit_keys(self); | |
28 | return self; | |
29 | } | |
30 | ||
f9224c5c ACM |
31 | static size_t hist_entry__append_browser(struct hist_entry *self, |
32 | newtComponent listbox, u64 total) | |
33 | { | |
34 | char bf[1024]; | |
35 | size_t len; | |
36 | FILE *fp; | |
37 | ||
38 | if (symbol_conf.exclude_other && !self->parent) | |
39 | return 0; | |
40 | ||
41 | fp = fmemopen(bf, sizeof(bf), "w"); | |
42 | if (fp == NULL) | |
43 | return 0; | |
44 | ||
45 | len = hist_entry__fprintf(self, NULL, false, 0, fp, total); | |
46 | ||
47 | fclose(fp); | |
48 | newtListboxAppendEntry(listbox, bf, self); | |
49 | return len; | |
50 | } | |
51 | ||
52 | static void hist_entry__annotate_browser(struct hist_entry *self) | |
53 | { | |
54 | FILE *fp; | |
cb7afb70 | 55 | int cols, rows; |
f9224c5c ACM |
56 | newtComponent form, listbox; |
57 | struct newtExitStruct es; | |
58 | char *str; | |
59 | size_t line_len, max_line_len = 0; | |
60 | size_t max_usable_width; | |
61 | char *line = NULL; | |
62 | ||
63 | if (self->sym == NULL) | |
64 | return; | |
65 | ||
d06d92b7 | 66 | if (asprintf(&str, "perf annotate %s 2>&1 | expand", self->sym->name) < 0) |
f9224c5c ACM |
67 | return; |
68 | ||
69 | fp = popen(str, "r"); | |
70 | if (fp == NULL) | |
71 | goto out_free_str; | |
72 | ||
73 | newtPushHelpLine("Press ESC to exit"); | |
cb7afb70 ACM |
74 | newtGetScreenSize(&cols, &rows); |
75 | listbox = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL); | |
f9224c5c ACM |
76 | |
77 | while (!feof(fp)) { | |
78 | if (getline(&line, &line_len, fp) < 0 || !line_len) | |
79 | break; | |
80 | while (line_len != 0 && isspace(line[line_len - 1])) | |
81 | line[--line_len] = '\0'; | |
82 | ||
83 | if (line_len > max_line_len) | |
84 | max_line_len = line_len; | |
85 | newtListboxAppendEntry(listbox, line, NULL); | |
86 | } | |
87 | fclose(fp); | |
88 | free(line); | |
89 | ||
cb7afb70 | 90 | max_usable_width = cols - 22; |
f9224c5c ACM |
91 | if (max_line_len > max_usable_width) |
92 | max_line_len = max_usable_width; | |
93 | ||
94 | newtListboxSetWidth(listbox, max_line_len); | |
95 | ||
cb7afb70 | 96 | newtCenteredWindow(max_line_len + 2, rows - 5, self->sym->name); |
7081e087 | 97 | form = newt_form__new(); |
f9224c5c ACM |
98 | newtFormAddComponents(form, listbox, NULL); |
99 | ||
100 | newtFormRun(form, &es); | |
101 | newtFormDestroy(form); | |
102 | newtPopWindow(); | |
103 | newtPopHelpLine(); | |
104 | out_free_str: | |
105 | free(str); | |
106 | } | |
107 | ||
108 | void perf_session__browse_hists(struct rb_root *hists, u64 session_total, | |
109 | const char *helpline) | |
110 | { | |
111 | struct sort_entry *se; | |
112 | struct rb_node *nd; | |
113 | unsigned int width; | |
114 | char *col_width = symbol_conf.col_width_list_str; | |
cb7afb70 | 115 | int rows; |
f9224c5c ACM |
116 | size_t max_len = 0; |
117 | char str[1024]; | |
118 | newtComponent form, listbox; | |
119 | struct newtExitStruct es; | |
120 | ||
121 | snprintf(str, sizeof(str), "Samples: %Ld", session_total); | |
122 | newtDrawRootText(0, 0, str); | |
123 | newtPushHelpLine(helpline); | |
124 | ||
cb7afb70 | 125 | newtGetScreenSize(NULL, &rows); |
f9224c5c | 126 | |
7081e087 | 127 | form = newt_form__new(); |
f9224c5c | 128 | |
cb7afb70 ACM |
129 | listbox = newtListbox(1, 1, rows - 2, (NEWT_FLAG_SCROLL | |
130 | NEWT_FLAG_BORDER | | |
131 | NEWT_FLAG_RETURNEXIT)); | |
f9224c5c ACM |
132 | |
133 | list_for_each_entry(se, &hist_entry__sort_list, list) { | |
134 | if (se->elide) | |
135 | continue; | |
136 | width = strlen(se->header); | |
137 | if (se->width) { | |
138 | if (symbol_conf.col_width_list_str) { | |
139 | if (col_width) { | |
140 | *se->width = atoi(col_width); | |
141 | col_width = strchr(col_width, ','); | |
142 | if (col_width) | |
143 | ++col_width; | |
144 | } | |
145 | } | |
146 | *se->width = max(*se->width, width); | |
147 | } | |
148 | } | |
149 | ||
150 | for (nd = rb_first(hists); nd; nd = rb_next(nd)) { | |
151 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | |
152 | size_t len = hist_entry__append_browser(h, listbox, session_total); | |
153 | if (len > max_len) | |
154 | max_len = len; | |
155 | } | |
156 | ||
157 | newtListboxSetWidth(listbox, max_len); | |
158 | newtFormAddComponents(form, listbox, NULL); | |
159 | ||
160 | while (1) { | |
161 | struct hist_entry *selection; | |
162 | ||
163 | newtFormRun(form, &es); | |
164 | if (es.reason == NEWT_EXIT_HOTKEY) | |
165 | break; | |
166 | selection = newtListboxGetCurrent(listbox); | |
167 | hist_entry__annotate_browser(selection); | |
168 | } | |
169 | ||
170 | newtFormDestroy(form); | |
171 | } | |
172 | ||
173 | int browser__show_help(const char *format, va_list ap) | |
174 | { | |
175 | int ret; | |
176 | static int backlog; | |
177 | static char msg[1024]; | |
178 | ||
179 | ret = vsnprintf(msg + backlog, sizeof(msg) - backlog, format, ap); | |
180 | backlog += ret; | |
181 | ||
182 | if (msg[backlog - 1] == '\n') { | |
183 | newtPopHelpLine(); | |
184 | newtPushHelpLine(msg); | |
185 | newtRefresh(); | |
186 | backlog = 0; | |
187 | } | |
188 | ||
189 | return ret; | |
190 | } | |
191 | ||
f9224c5c ACM |
192 | void setup_browser(void) |
193 | { | |
194 | if (!isatty(1)) | |
195 | return; | |
196 | ||
197 | use_browser = true; | |
198 | newtInit(); | |
199 | newtCls(); | |
200 | newtPushHelpLine(" "); | |
201 | } | |
202 | ||
203 | void exit_browser(void) | |
204 | { | |
205 | if (use_browser) | |
206 | newtFinished(); | |
207 | } |