summaryrefslogblamecommitdiff
path: root/tools/perf/util/newt.c
blob: 3c2ef95d940a4072e73f6589d65a0eed36ca37a3 (plain) (tree)
1
2
3
4
5
6
7





                   
                            






                    















                                                        























                                                                          
                       









                                          
                                                                                  






                                              

                                                                













                                                                    
                                     




                                                   
                                                                        
                                
















                                                                         
                 








                                                                  
                                       
 
                                
 


                                                                      








































                                                                                   

                                    



                                                      
 

                                                                         

                       
                                                     
                                  
                                                    






                              










                              
                                   
 




                                                                     
                               
         
 
#define _GNU_SOURCE
#include <stdio.h>
#undef _GNU_SOURCE

#include <stdlib.h>
#include <newt.h>
#include <sys/ttydefaults.h>

#include "cache.h"
#include "hist.h"
#include "session.h"
#include "sort.h"
#include "symbol.h"

static void newt_form__set_exit_keys(newtComponent self)
{
	newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
	newtFormAddHotKey(self, 'Q');
	newtFormAddHotKey(self, 'q');
	newtFormAddHotKey(self, CTRL('c'));
}

static newtComponent newt_form__new(void)
{
	newtComponent self = newtForm(NULL, NULL, 0);
	if (self)
		newt_form__set_exit_keys(self);
	return self;
}

static size_t hist_entry__append_browser(struct hist_entry *self,
					 newtComponent listbox, u64 total)
{
	char bf[1024];
	size_t len;
	FILE *fp;

	if (symbol_conf.exclude_other && !self->parent)
		return 0;

	fp = fmemopen(bf, sizeof(bf), "w");
	if (fp == NULL)
		return 0;

	len = hist_entry__fprintf(self, NULL, false, 0, fp, total);

	fclose(fp);
	newtListboxAppendEntry(listbox, bf, self);
	return len;
}

static void hist_entry__annotate_browser(struct hist_entry *self)
{
	FILE *fp;
	int cols, rows;
	newtComponent form, listbox;
	struct newtExitStruct es;
	char *str;
	size_t line_len, max_line_len = 0;
	size_t max_usable_width;
	char *line = NULL;

	if (self->sym == NULL)
		return;

	if (asprintf(&str, "perf annotate %s 2>&1 | expand", self->sym->name) < 0)
		return;

	fp = popen(str, "r");
	if (fp == NULL)
		goto out_free_str;

	newtPushHelpLine("Press ESC to exit");
	newtGetScreenSize(&cols, &rows);
	listbox = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL);

	while (!feof(fp)) {
		if (getline(&line, &line_len, fp) < 0 || !line_len)
			break;
		while (line_len != 0 && isspace(line[line_len - 1]))
			line[--line_len] = '\0';

		if (line_len > max_line_len)
			max_line_len = line_len;
		newtListboxAppendEntry(listbox, line, NULL);
	}
	fclose(fp);
	free(line);

	max_usable_width = cols - 22;
	if (max_line_len > max_usable_width)
		max_line_len = max_usable_width;

	newtListboxSetWidth(listbox, max_line_len);

	newtCenteredWindow(max_line_len + 2, rows - 5, self->sym->name);
	form = newt_form__new();
	newtFormAddComponents(form, listbox, NULL);

	newtFormRun(form, &es);
	newtFormDestroy(form);
	newtPopWindow();
	newtPopHelpLine();
out_free_str:
	free(str);
}

void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
				const char *helpline)
{
	struct sort_entry *se;
	struct rb_node *nd;
	unsigned int width;
	char *col_width = symbol_conf.col_width_list_str;
	int rows;
	size_t max_len = 0;
	char str[1024];
	newtComponent form, listbox;
	struct newtExitStruct es;

	snprintf(str, sizeof(str), "Samples: %Ld", session_total);
	newtDrawRootText(0, 0, str);
	newtPushHelpLine(helpline);

	newtGetScreenSize(NULL, &rows);

	form = newt_form__new();

	listbox = newtListbox(1, 1, rows - 2, (NEWT_FLAG_SCROLL |
					       NEWT_FLAG_BORDER |
					       NEWT_FLAG_RETURNEXIT));

	list_for_each_entry(se, &hist_entry__sort_list, list) {
		if (se->elide)
			continue;
		width = strlen(se->header);
		if (se->width) {
			if (symbol_conf.col_width_list_str) {
				if (col_width) {
					*se->width = atoi(col_width);
					col_width = strchr(col_width, ',');
					if (col_width)
						++col_width;
				}
			}
			*se->width = max(*se->width, width);
		}
	}

	for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
		size_t len = hist_entry__append_browser(h, listbox, session_total);
		if (len > max_len)
			max_len = len;
	}

	newtListboxSetWidth(listbox, max_len);
	newtFormAddComponents(form, listbox, NULL);

	while (1) {
		struct hist_entry *selection;

		newtFormRun(form, &es);
		if (es.reason == NEWT_EXIT_HOTKEY)
			break;
		selection = newtListboxGetCurrent(listbox);
		hist_entry__annotate_browser(selection);
	}

	newtFormDestroy(form);
}

static char browser__last_msg[1024];

int browser__show_help(const char *format, va_list ap)
{
	int ret;
	static int backlog;

        ret = vsnprintf(browser__last_msg + backlog,
			sizeof(browser__last_msg) - backlog, format, ap);
	backlog += ret;

	if (browser__last_msg[backlog - 1] == '\n') {
		newtPopHelpLine();
		newtPushHelpLine(browser__last_msg);
		newtRefresh();
		backlog = 0;
	}

	return ret;
}

void setup_browser(void)
{
	if (!isatty(1))
		return;

	use_browser = true;
	newtInit();
	newtCls();
	newtPushHelpLine(" ");
}

void exit_browser(bool wait_for_ok)
{
	if (use_browser) {
		if (wait_for_ok) {
			char title[] = "Fatal Error", ok[] = "Ok";
			newtWinMessage(title, ok, browser__last_msg);
		}
		newtFinished();
	}
}