9 #include "jdb_disasm.h"
10 #include "jdb_input.h"
11 #include "jdb_module.h"
12 #include "jdb_screen.h"
13 #include "jdb_symbol.h"
14 #include "jdb_regex.h"
16 #include "jdb_tbuf_output.h"
18 #include "kernel_console.h"
22 #include "static_init.h"
25 class Jdb_tbuf_show : public Jdb_module
28 Jdb_tbuf_show() FIASCO_INIT;
31 static char _search_str[40];
32 static char _filter_str[40];
33 static char _buffer_str[512];
34 static Mword _status_type;
38 static Mword _nr_pos[10];
39 static Mword y_offset;
43 Index_mode = 0, // number of event
44 Tsc_delta_mode = 1, // tsc ticks starting from last event
45 Tsc_ref_mode = 2, // tsc ticks starting from reference event
46 Tsc_start_mode = 3, // tsc ticks starting from 0
47 Kclock_ref_mode = 4, // kernel clock units (us) since reference event
48 Kclock_start_mode = 5, // kernel clock units (us) since start of system
49 Pmc1_delta_mode = 6, // ticks of ctr 1 starting from last event
50 Pmc2_delta_mode = 7, // ticks of ctr 2 starting from last event
51 Pmc1_ref_mode = 8, // ticks of ctr 1 starting from reference event
52 Pmc2_ref_mode = 9, // ticks of ctr 2 starting from reference event
73 char Jdb_tbuf_show::_search_str[40];
74 char Jdb_tbuf_show::_filter_str[40];
75 char Jdb_tbuf_show::_buffer_str[512];
76 Mword Jdb_tbuf_show::_status_type;
77 Mword Jdb_tbuf_show::_absy;
78 Mword Jdb_tbuf_show::_nr_cur;
79 Mword Jdb_tbuf_show::_nr_ref;
80 Mword Jdb_tbuf_show::_nr_pos[10] = { Nil, Nil, Nil, Nil, Nil,
81 Nil, Nil, Nil, Nil, Nil };
83 Mword Jdb_tbuf_show::y_offset = 0;
86 Jdb_tbuf_show::error(const char * const msg)
88 Jdb::printf_statline("tbuf", 0, "\033[31;1m=== %s! ===\033[m", msg);
89 _status_type = Status_error;
93 Jdb_tbuf_show::get_string(char *string, unsigned size)
95 for (unsigned pos=strlen(string); ; )
97 switch(int c=Jdb_core::getchar())
103 string[--pos] = '\0';
109 Jdb::abort_command();
126 Jdb_tbuf_show::show_perf_event_unit_mask_entry(Mword nr, Mword idx,
127 Mword unit_mask, int exclusive)
132 Perf_cnt::get_unit_mask_entry(nr, idx, &value, &desc);
134 desc = "(no description?)";
135 printf(" %c %02lx %.59s\033[K",
136 exclusive ? unit_mask == value ? '+' : ' '
137 : unit_mask & value ? '+' : ' ',
142 Jdb_tbuf_show::show_perf_event(Mword nr)
144 const char *name, *desc;
146 Mword add_kcnt = Config::Jdb_accounting ? Kern_cnt_max : 0;
150 const char * const s = Kern_cnt::get_str(nr);
151 printf(" %-26.26s %.49s\033[K", s, "(kernel event counter)");
155 Perf_cnt::get_perf_event(nr - add_kcnt, &evntsel, &name, &desc);
159 desc = "(no description)";
161 printf("%02x %-26.26s %.49s\033[K", evntsel, name, desc);
165 Jdb_tbuf_show::select_perf_event_unit_mask(Mword nr, Mword unit_mask)
171 Mword cols = Jdb_screen::cols() - 1;
173 Mword default_value, nvalues, value;
174 Perf_cnt::Unit_mask_type type;
177 Perf_cnt::get_unit_mask(nr, &type, &default_value, &nvalues);
178 int exclusive = (type == Perf_cnt::Exclusive);
180 if (type == Perf_cnt::None)
183 if (type == Perf_cnt::Fixed || (nvalues < 1))
184 return default_value;
188 Perf_cnt::get_unit_mask_entry(nr, 0, &value, &desc);
195 Jdb::printf_statline("tbuf", "<Space>=set mask <CR>=done", "P?");
197 Jdb::cursor(Tbuf_start_line, 1);
199 show_perf_event(nr + (Config::Jdb_accounting ? Kern_cnt_max : 0));
200 printf("\033[m\033[K\n"
202 " \033[1;32mSelect Event Mask (%s):\033[m\033[K\n"
203 "\033[K\n", exclusive ? "exclusive" : "bitmap");
209 Jdb::cursor(Tbuf_start_line+4, 1);
210 for (i=0; i<lines; i++)
212 show_perf_event_unit_mask_entry(nr, i, unit_mask, exclusive);
215 for (; i<Jdb_screen::height()-Tbuf_start_line-5; i++)
218 for (bool redraw=false; !redraw; )
224 Jdb::cursor(addy+Tbuf_start_line+4, 1);
225 putstr(Jdb::esc_emph);
226 show_perf_event_unit_mask_entry(nr, absy+addy, unit_mask, exclusive);
228 Jdb::cursor(addy+Tbuf_start_line+4, 1);
229 c = Jdb_core::getchar();
230 show_perf_event_unit_mask_entry(nr, absy+addy, unit_mask, exclusive);
231 Perf_cnt::get_unit_mask_entry(nr, absy+addy, &value, &dummy);
233 if (Jdb::std_cursor_key(c, cols, lines, max_absy,
234 &absy, &addy, 0, &redraw))
253 if (Jdb::is_toplevel_cmd(c))
261 Jdb_tbuf_show::select_perf_event(Mword event)
265 Mword add_kcnt = Config::Jdb_accounting ? Kern_cnt_max : 0;
266 Mword nevents = Perf_cnt::get_max_perf_event() + add_kcnt;
267 Mword lines = (nevents < Jdb_screen::height()-6)
269 : Jdb_screen::height()-6;
270 Mword cols = Jdb_screen::cols() - 1;
271 Mword max_absy = nevents-lines;
274 // libperfctr not linked
280 Jdb::printf_statline("tbuf", "<CR>=select", "P?");
282 Jdb::cursor(Tbuf_start_line, 1);
283 printf("%sSelect Performance Counter\033[m\033[K\n\033[K", Jdb::esc_emph2);
285 if (event & 0x80000000)
289 Perf_cnt::split_event(event, &evntsel, &unit_mask);
290 addy = Perf_cnt::lookup_event(evntsel);
299 absy += (addy-lines+1);
307 Jdb::cursor(Tbuf_start_line+2, 1);
308 for (i=0; i<lines; i++)
310 show_perf_event(absy+i);
313 for (; i<Jdb_screen::height()-Tbuf_start_line-2; i++)
316 for (bool redraw=false; !redraw; )
320 Jdb::cursor(addy+Tbuf_start_line+2, 1);
321 putstr(Jdb::esc_emph);
322 show_perf_event(absy+addy);
324 Jdb::cursor(addy+Tbuf_start_line+2, 1);
325 int c = Jdb_core::getchar();
326 show_perf_event(absy+addy);
327 if (Jdb::std_cursor_key(c, cols, lines, max_absy,
328 &absy, &addy, 0, &redraw))
336 return absy | 0x80000000;
339 Perf_cnt::get_perf_event(absy, &evntsel, &dummy, &dummy);
340 unit_mask = select_perf_event_unit_mask(absy, unit_mask);
341 if (unit_mask != Nil)
343 Perf_cnt::combine_event(evntsel, unit_mask, &event);
350 if (Jdb::is_toplevel_cmd(c))
359 Jdb_tbuf_show::show_events(Mword n, Mword ref, Mword count, Unsigned8 mode,
360 Unsigned8 time_mode, int long_output)
363 Unsigned32 ref_kclock, ref_pmc1, ref_pmc2;
366 Jdb_tbuf::event(ref, &dummy, &ref_kclock, &ref_tsc, &ref_pmc1, &ref_pmc2);
368 for (i=0; i<count; i++)
374 Unsigned32 kclock, upmc1, upmc2;
376 Kconsole::console()->getchar_chance();
378 if (!Jdb_tbuf::event(n, &number, &kclock, &utsc, &upmc1, &upmc2))
384 Jdb_tbuf_output::print_entry(n, _buffer_str, sizeof(_buffer_str));
386 if (!Jdb_tbuf::diff_tsc(n, &dtsc))
397 for (int i=0; i<10; i++)
398 if (number == _nr_pos[i])
406 char s_tsc_dc[13], s_tsc_ds[15], s_tsc_sc[13], s_tsc_ss[15];
407 Jdb::write_ll_dec(dtsc, s_tsc_dc, sizeof(s_tsc_dc), false);
408 Jdb::write_tsc_s (dtsc, s_tsc_ds, sizeof(s_tsc_ds), false);
409 Jdb::write_ll_dec(utsc, s_tsc_sc, sizeof(s_tsc_sc), false);
410 Jdb::write_tsc_s (utsc, s_tsc_ss, sizeof(s_tsc_ss), false);
412 printf("%-3s%10lu. %120.120s %13.13s (%14.14s) %13.13s (%14.14s) kclk=%d\n",
413 s, number, _buffer_str+y_offset, s_tsc_dc, s_tsc_ds, s_tsc_sc, s_tsc_ss, kclock);
418 Jdb_tbuf_output::print_entry(n, _buffer_str, sizeof(_buffer_str));
422 snprintf(s, sizeof(s), "%12lu", number);
425 if (!Jdb_tbuf::diff_tsc(n, &dtsc))
429 case 0: Jdb::write_ll_hex(dtsc, s, sizeof(s), false); break;
430 case 1: Jdb::write_tsc (dtsc, s, sizeof(s), false); break;
431 case 2: Jdb::write_ll_dec(dtsc, s, sizeof(s), false); break;
435 dtsc = (n == ref) ? 0 : utsc - ref_tsc;
438 case 0: Jdb::write_ll_hex(dtsc, s, sizeof(s), true); break;
439 case 1: Jdb::write_tsc (dtsc, s, sizeof(s), true); break;
440 case 2: Jdb::write_ll_dec(dtsc, s, sizeof(s), true); break;
447 case 0: Jdb::write_ll_hex(dtsc, s, sizeof(s), true); break;
448 case 1: Jdb::write_tsc (dtsc, s, sizeof(s), false); break;
449 case 2: Jdb::write_ll_dec(dtsc, s, sizeof(s), true); break;
452 case Kclock_ref_mode:
453 if (kclock == ref_kclock)
454 snprintf(s, sizeof(s), "%12u", 0);
458 Jdb::write_ll_hex((Unsigned64)kclock-ref_kclock,
461 snprintf(s, sizeof(s), "%+12d", kclock-ref_kclock);
464 case Kclock_start_mode:
465 snprintf(s, sizeof(s), time_mode != 1 ? "%012x" : "%12u",
468 case Pmc1_delta_mode:
469 case Pmc2_delta_mode:
470 if (!Jdb_tbuf::diff_pmc(n, (mode-Pmc1_delta_mode), &dpmc))
472 Jdb::write_ll_dec((Signed64)dpmc, s, sizeof(s), false);
475 dpmc = (n == ref) ? 0 : upmc1 - ref_pmc1;
476 Jdb::write_ll_dec((Signed64)dpmc, s, sizeof(s), true);
479 dpmc = (n == ref) ? 0 : upmc2 - ref_pmc2;
480 Jdb::write_ll_dec((Signed64)dpmc, s, sizeof(s), true);
489 for (int i=0; i<10; i++)
490 if (number == _nr_pos[i])
496 printf("%s%-*.*s %12s\033[m%s",
497 c, Jdb_screen::width()-13, (int)Jdb_screen::width()-13,
498 _buffer_str+y_offset, s, count != 1 ? "\n" : "");
504 // search in tracebuffer
506 Jdb_tbuf_show::search(Mword start, Mword entries, const char *str,
514 if (Jdb_regex::avail() && !Jdb_regex::start(str))
516 error("Error in regular expression");
520 for (Mword n=direction==1 ? start-1 : start+1; ; (direction==1) ? n-- : n++)
522 static char buffer[120];
524 // don't cycle through entries more than once
525 // (should not happen due to the following check)
529 if (!Jdb_tbuf::event_valid(n))
531 error(direction ? "Begin of tracebuffer reached"
532 : "End of tracebuffer reached");
536 if (!Jdb_tbuf::event_valid(n))
537 n = (direction==1) ? entries-1 : 0;
539 Jdb_tbuf_output::print_entry(n, buffer, sizeof(buffer));
545 Jdb::cursor(Jdb_screen::height(), 79);
546 putchar("|/-\\"[progress++]);
550 if (Jdb_regex::avail() && Jdb_regex::find(buffer, 0, 0))
555 else if (strstr(buffer, str))
563 Jdb::cursor(Jdb_screen::height(), 79);
570 Jdb_tbuf_show::show()
572 static Unsigned8 mode = Index_mode;
573 static Unsigned8 time_mode = 1;
574 static Unsigned8 direction = 0;
577 Jdb_tbuf_output::set_filter(_filter_str, &entries);
581 Mword refy; // idx of reference event
582 Mword posy[10]; // idx of mark{0..9}
583 Mword addy; // cursor position starting from top of screen
584 Mword lines = Jdb_screen::height()-4;
585 Mword cols = Jdb_screen::cols() - 1;
589 if (Jdb_tbuf::max_entries() < lines)
590 lines = Jdb_tbuf::max_entries();
596 Mword max_absy = entries > lines ? entries - lines : 0;
598 // Search reference element. If not found, use last entry.
599 if ((refy = Jdb_tbuf::search_to_idx(_nr_ref)) >= (Mword)-2)
605 // Search mark {0..9}. If not found, set Nil.
607 posy[n] = Jdb_tbuf::search_to_idx(_nr_pos[n]);
609 // Search current position. If beyond buffer, goto first entry.
610 if ((addy = Jdb_tbuf::search_to_idx(_nr_cur)))
619 Mword count, perf_event[2];
620 Mword perf_user[2] = { 0, 0 };
621 Mword perf_kern[2] = { 0, 0 };
622 Mword perf_edge[2] = { 0, 0 };
623 const char *perf_mode[2], *perf_name[2];
625 for (Mword i=0; i<2; i++)
626 if (Kern_cnt::mode (i, &perf_mode[i], &perf_name[i], &perf_event[i]) ||
627 Perf_cnt::mode (i, &perf_mode[i], &perf_name[i], &perf_event[i],
628 &perf_user[i], &perf_kern[i], &perf_edge[i])) {}
630 static const char * const mode_str[] =
631 { "index", "tsc diff", "tsc rel", "tsc start", "kclock rel",
632 "kclock", "pmc1 diff", "pmc2 diff", "pmc1 rel", "pmc2 rel" };
634 const char *perf_type = Perf_cnt::perf_type();
637 printf("%3lu%% of %-6lu Perf:%-4s 1="L4_PTR_FMT
638 "(%s%s\033[m%s%s%s\033[m)\033[K",
639 Jdb_tbuf::unfiltered_entries()*100/Jdb_tbuf::max_entries(),
640 Jdb_tbuf::max_entries(),
641 perf_type, perf_event[0], Jdb::esc_emph, perf_mode[0],
642 perf_name[0] && *perf_name[0] ? ":" : "",
643 mode==Pmc1_delta_mode || mode==Pmc1_ref_mode ? Jdb::esc_emph : "",
648 "%24s 2="L4_PTR_FMT"(%s%s\033[m%s%s%s\033[m)\033[K\n",
649 mode_str[(int)mode], "",
650 perf_event[1], Jdb::esc_emph, perf_mode[1],
651 perf_name[1] && *perf_name[1] ? ":" : "",
652 mode==Pmc2_delta_mode || mode==Pmc2_ref_mode ? Jdb::esc_emph : "",
657 printf("\033[31m%3lu%% filtered\033[m\n",
658 entries*100/Jdb_tbuf::max_entries());
660 for (Mword i=3; i<Tbuf_start_line; i++)
663 show_events(_absy, refy, lines, mode, time_mode, 0);
667 for (Mword i=Tbuf_start_line+lines; i<Jdb_screen::height(); i++)
670 _status_type = Status_redraw;
673 for (bool redraw=false; !redraw;)
675 Tb_entry *pair_event = 0;
679 Unsigned8 d = 0; // default search direction is forward
681 if (_status_type == Status_redraw)
683 Jdb::printf_statline("tbuf", "/?nN=search sj=mark c=clear r=ref "
684 "F=filter D=dump P=perf <CR>=select", "_");
685 _status_type = Status_ok;
687 else if (_status_type == Status_error)
688 _status_type = Status_redraw;
692 // search for paired ipc event
693 pair_event = Jdb_tbuf::ipc_pair_event(_absy+addy, &type);
695 // search for paired pagefault event
696 pair_event = Jdb_tbuf::pf_pair_event(_absy+addy, &type);
699 pair_y = Jdb_tbuf::idx(pair_event);
700 if (pair_y < _absy || pair_y >= _absy+lines)
705 Jdb::cursor(pair_y-_absy+Tbuf_start_line, 1);
706 putstr(Jdb::esc_emph);
709 case Jdb_tbuf::Result: putstr("+++>"); break;
710 case Jdb_tbuf::Event: putstr("<+++"); break;
716 Jdb::cursor(addy+Tbuf_start_line, 1);
717 putstr(Jdb::esc_emph);
718 show_events(_absy+addy, refy, 1, mode, time_mode, 0);
720 Jdb::cursor(addy+Tbuf_start_line, 1);
721 c=Jdb_core::getchar();
722 show_events(_absy+addy, refy, 1, mode, time_mode, 0);
725 Jdb::cursor(pair_y-_absy+Tbuf_start_line, 1);
726 show_events(pair_y, refy, 1, mode, time_mode, 0);
729 if (Jdb::std_cursor_key(c, cols, lines, max_absy,
730 &_absy, &addy, 0, &redraw))
744 if (y_offset<sizeof(_buffer_str)-82)
747 y_offset = sizeof(_buffer_str)-72;
751 case 'F': // filter view by regex
752 Jdb::printf_statline("tbuf", 0, "Filter(%s)=%s",
753 Jdb_regex::avail() ? "regex" : "instr",
755 _status_type = Status_redraw;
756 Jdb::cursor(Jdb_screen::height(), 21+strlen(_filter_str));
757 if (!get_string(_filter_str, sizeof(_filter_str)))
759 if (!Jdb_tbuf_output::set_filter(_filter_str, &entries))
761 error("Error in regular expression");
767 case 'D': // dump to console
768 if (!Kconsole::console()->find_console(Console::GZIP))
770 Jdb::cursor(Jdb_screen::height(), 10);
773 if (Jdb_input::get_mword(&count, 7, 10))
777 Kconsole::console()->start_exclusive(Console::GZIP);
778 show_events(_absy, refy, count, mode, time_mode, 1);
779 Kconsole::console()->end_exclusive(Console::GZIP);
783 _status_type = Status_redraw;
785 case 'P': // set performance counter
788 int user, kern, edge, nr;
790 Jdb::printf_statline("tbuf", "1..2=select counter", "P");
791 Jdb::cursor(Jdb_screen::height(), 8);
794 nr = Jdb_core::getchar();
797 if (nr >= '1' && nr <= '2')
804 event = perf_event[nr];
805 user = perf_user[nr];
806 kern = perf_kern[nr];
807 edge = perf_edge[nr];
808 Jdb::printf_statline("tbuf", "d=duration e=edge u=user "
809 "k=kern +=both -=none ?=event",
810 "P%c", (char)'1'+nr);
812 Jdb::cursor(Jdb_screen::height(), 9);
813 switch(c=Jdb_core::getchar())
815 case '+': user = 1; kern = 1; break;
816 case '-': user = 0; kern = 0; event = 0; break;
817 case 'u': user = 1; kern = 0; break;
818 case 'k': user = 0; kern = 1; break;
819 case 'd': edge = 0; break;
820 case 'e': edge = 1; break;
822 case '_': if ((e = select_perf_event(event)) == Nil)
830 default: Jdb_input::get_mword(&event, 4, 16, c);
834 if (!Kern_cnt::setup_pmc(nr, event) &&
835 !Perf_cnt::setup_pmc(nr, event, user, kern, edge))
836 Tb_entry::set_rdcnt(nr, 0);
841 case KEY_RETURN: // disassemble eip of current entry
845 if (Jdb_tbuf_output::thread_ip(_absy+addy, &t, &eip))
847 if (Jdb_disasm::avail())
849 if (!Jdb_disasm::show(eip, t->space(), 1, 1))
853 { // hacky, we should get disasm working for arm too
854 // (at least without the disassembly itself)
855 printf("\n==========================\n"
857 "==========================\n", eip);
865 Jdb_tbuf_output::toggle_names();
868 case KEY_CURSOR_LEFT: // mode switch
869 if (mode == Index_mode)
870 mode = Pmc2_ref_mode;
875 case KEY_CURSOR_RIGHT: // mode switch
877 if (mode > Pmc2_ref_mode)
881 case ' ': // mode switch
882 if (mode != Index_mode)
884 time_mode = (time_mode+1) % 3;
888 case 'c': // clear tracebuffer
889 Jdb_tbuf::clear_tbuf();
897 case 's': // set mark
898 Jdb::printf_statline("tbuf", 0, "set mark [0-9] ");
899 _status_type = Status_redraw;
900 c = Jdb_core::getchar();
901 if (!entries || c < '0' || c > '9')
903 error("Invalid marker");
907 posy[n] = _absy + addy;
908 _nr_pos[n] = Jdb_tbuf::lookup(_absy+addy)->number();
911 case 'r': // set reference entry
915 _nr_ref = Jdb_tbuf::lookup(_absy+addy)->number();
918 case 'j': // jump to mark or reference element
919 Jdb::printf_statline("tbuf", 0, "jump to mark [0-9] or ref [r] ");
920 _status_type = Status_redraw;
921 c = Jdb_core::getchar();
922 if ((c < '0' || c > '9') && c != 'r')
924 error("Invalid marker");
927 n = (c == 'r') ? refy : posy[c-'0'];
933 else if (n == (Mword)-2)
935 error("Mark not visible within current filter");
939 case '?': // search backward
942 case '/': // search forward
944 // search in tracebuffer events
945 Jdb::printf_statline("tbuf", 0, "%s=%s",
946 Jdb_regex::avail() ? "Regexp" : "Search",
948 _status_type = Status_redraw;
949 Jdb::cursor(Jdb_screen::height(), 14+strlen(_search_str));
950 if (!get_string(_search_str, sizeof(_search_str)) ||
954 case 'n': // search next
955 case 'N': // search next reverse
956 n = search(_absy+addy, entries, _search_str,
957 c == 'N' ? !direction : direction);
962 if (n < _absy || n > _absy+lines-1)
972 if (_absy > max_absy)
985 Jdb::abort_command();
988 if (Jdb::is_toplevel_cmd(c))
995 _nr_cur = (e = Jdb_tbuf::lookup(_absy+addy)) ? e->number() : 0;
999 Jdb_module::Action_code
1000 Jdb_tbuf_show::action(int cmd, void *&, char const *&, int &)
1009 if (Kconsole::console()->find_console(Console::GZIP))
1011 Jdb_tbuf_output::set_filter(_filter_str, 0);
1012 Kconsole::console()->start_exclusive(Console::GZIP);
1013 show_events(0, 0, 1000000, 0, 0, 1);
1014 Kconsole::console()->end_exclusive(Console::GZIP);
1023 Jdb_module::Cmd const *
1024 Jdb_tbuf_show::cmds() const
1028 { 0, "T", "tbuf", "",
1029 "T{P{+|-|k|u|<event>}}\tenter tracebuffer, on/off/kernel/user perf",
1031 { 1, "Tgzip", "", "", 0 /* invisible */, 0 },
1039 Jdb_tbuf_show::num_cmds() const
1045 Jdb_tbuf_show::Jdb_tbuf_show()
1046 : Jdb_module("MONITORING")
1049 static Jdb_tbuf_show jdb_tbuf_show INIT_PRIORITY(JDB_MODULE_INIT_PRIO);