latencytop-0.5ubuntu3/0000775000000000000000000000000011542643735011770 5ustar latencytop-0.5ubuntu3/latencytop.trans0000664000000000000000000001252711175603262015223 0ustar # 1 vfs_read Reading from file 1 vfs_write Writing to file 1 __mark_inode_dirty Marking inode dirty 1 vfs_readdir Reading directory content 1 vfs_unlink Unlinking file 1 blocking_notifier_call_chain Blocking notifier 1 lock_super Superblock lock contention 1 vfs_create Creating a file # 2 __bread Synchronous buffer read 2 do_generic_mapping_read Reading file data 2 sock_sendmsg Sending data over socket 2 do_sys_open Opening file 2 do_sys_poll Waiting for event (poll) 2 core_sys_select Waiting for event (select) 2 proc_reg_read Reading from /proc file 2 __pollwait Waiting for event (poll) 2 sys_fcntl FCNTL system call 2 scsi_error_handler SCSI error handler 2 proc_root_readdir Reading /proc directory 2 ksoftirqd Waking ksoftirqd 2 worker_thread . 2 do_unlinkat Unlinking file 2 __wait_on_buffer Waiting for buffer IO to complete 2 pdflush pdflush() kernel thread 2 kjournald kjournald() kernel thread 2 blkdev_ioctl block device IOCTL 2 kauditd_thread kernel audit daemon 2 tty_ioctl TTY IOCTL 2 __filemap_fdatawrite_range fdatasync system call 2 do_sync_write synchronous write 2 kthreadd kthreadd kernel thread 2 usb_port_resume Waking up USB device 2 usb_autoresume_device Waking up USB device 2 kswapd kswapd() kernel thread 2 md_thread Raid resync kernel thread 2 i915_wait_request Waiting for GPU command to complete 2 request_module Loading a kernel module # 3 tty_wait_until_sent Waiting for TTY to finish sending 3 pipe_read Reading from a pipe 3 pipe_write Writing to a pipe 3 pipe_wait Waiting for pipe data 3 read_block_bitmap Reading EXT3 block bitmaps 3 scsi_execute_req Executing raw SCSI command 3 sys_wait4 Waiting for a process to die 3 sr_media_change Checking for media change 3 sr_do_ioctl SCSI cdrom ioctl 3 sd_ioctl SCSI disk ioctl 3 sr_cd_check Checking CDROM media present 3 ext3_read_inode Reading EXT3 inode 3 htree_dirblock_to_tree Reading EXT3 directory htree 3 ext3_readdir Reading EXT3 directory 3 ext3_bread Synchronous EXT3 read 3 ext3_free_branches Unlinking file on EXT3 3 ext3_get_branch Reading EXT3 indirect blocks 3 ext3_find_entry EXT3: Looking for file 3 __ext3_get_inode_loc Reading EXT3 inode 3 ext3_delete_inode EXT3 deleting inode 3 sync_page Writing a page to disk 3 tty_poll Waiting for TTY data 3 tty_read Waiting for TTY input 3 tty_write Writing data to TTY 3 update_atime Updating inode atime 3 page_cache_sync_readahead Pagecache sync readahead 3 do_fork Fork() system call 3 sys_mkdirat Creating directory 3 lookup_create Creating file 3 inet_sendmsg Sending TCP/IP data 3 tcp_recvmsg Receiving TCP/IP data 3 link_path_walk Following symlink 3 path_walk Walking directory tree 3 sys_getdents Reading directory content 3 unix_stream_recvmsg Waiting for data on unix socket 3 ext3_mkdir EXT3: Creating a directory 3 journal_get_write_access EXT3: Waiting for journal access 3 synchronize_rcu Waiting for RCU 3 input_close_device Closing input device 3 mousedev_close_device Closing mouse device 3 mousedev_release Closing mouse device 3 mousedev_open Opening mouse device 3 kmsg_read Reading from dmesg 3 sys_futex Userspace lock contention 3 do_futex Userspace lock contention 3 vt_waitactive vt_waitactive IOCTL 3 acquire_console_sem Waiting for console access 3 filp_close Closing a file 3 sync_inode (f)syncing an inode to disk 3 ata_exec_internal_sg Executing internal ATA command 3 writeback_inodes Writing back inodes 3 ext3_orphan_add EXT3 adding orphan 3 ext3_mark_inode_dirty EXT3 marking inode dirty 3 ext3_unlink EXT3 unlinking file 3 ext3_create EXT3 Creating a file 3 log_do_checkpoint EXT3 journal checkpoint 3 generic_delete_inode Deleting an inode 3 proc_delete_inode Removing /proc file 3 do_truncate Truncating file 3 sys_execve Executing a program 3 journal_commit_transaction EXT3: committing transaction 3 __stop_machine_run Freezing the kernel (for module load) 3 sys_munmap unmapping memory 3 sys_mmap mmaping memory 3 sync_buffer Writing buffer to disk (synchronous) 3 inotify_inode_queue_event Inotify event 3 proc_lookup Looking up /proc file 3 generic_make_request Creating block layer request 3 get_request_wait Creating block layer request 3 alloc_page_vma Allocating a VMA #3 __d_lookup Looking up a dentry 3 blkdev_direct_IO Direct block device IO 3 sys_mprotect mprotect() system call 3 shrink_icache_memory reducing inode cache memory footprint 3 vfs_stat_fd stat() operation 3 cdrom_open opening cdrom device 3 sys_epoll_wait Waiting for event (epoll) 3 sync_sb_inodes Syncing inodes 3 tcp_connect TCP/IP connect 3 ata_scsi_ioctl ATA/SCSI disk ioctl 3 do_rmdir Removing directory 3 vfs_rmdir Removing directory 3 sys_flock flock() on a file 3 usbdev_open opening USB device 3 lock_kernel Big Kernel Lock contention 3 blk_execute_rq Submitting block IO 3 scsi_cmd_ioctl SCSI ioctl command 3 acpi_ec_transaction ACPI hardware access 3 journal_get_undo_access Waiting for EXT3 journal undo operation 3 i915_irq_wait Waiting for GPU interrupt 3 i915_gem_throttle_ioctl Throttling GPU while waiting for commands # # 5 do_page_fault Page fault 5 handle_mm_fault Page fault 5 filemap_fault Page fault 5 sync_filesystems Syncing filesystem 5 sys_nanosleep Application requested delay 5 sys_pause Application requested delay 5 evdev_read Reading keyboard/mouse input 5 do_fsync fsync() on a file (type 'F' for details) 5 __log_wait_for_space Waiting for EXT3 journal space latencytop-0.5ubuntu3/gtk_display.c0000664000000000000000000004330611175603262014445 0ustar /* * Copyright 2008, Benjamin Herrenschmidt * * This file is part of LatencyTOP * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this program in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "latencytop.h" static GtkWidget *main_window; static GtkListStore *targets_model; static GtkWidget *targets_view; static GtkListStore *results_model; static GtkWidget *results_view; static GtkListStore *backtrace_model; static GtkWidget *backtrace_view; static GtkWidget *countdown_label; static GtkWidget *freeze_button; static GdkPixbuf *global_icon; static GdkPixbuf *kthread_icon; static GdkPixbuf *process_icon; static unsigned int cur_target_pid; static int countdown; static int countdown_max = 30; static int countdown_frozen; static int ignore_sel; static int force_results; /* Column indices in the various trees */ enum { COL_R_CAUSE = 0, COL_R_MAX, COL_R_PERCENT, COL_R_LINE }; enum { COL_T_ICON = 0, COL_T_NAME, COL_T_MAX, COL_T_PROC, }; enum { COL_B_FUNC = 0, }; static void remove_all_targets(void) { gtk_list_store_clear(targets_model); } static void remove_all_results(void) { gtk_list_store_clear(results_model); gtk_list_store_clear(backtrace_model); } static gint compare_process(gconstpointer a, gconstpointer b) { const struct process *pa = a; const struct process *pb = b; return pb->max - pa->max; } static void insert_all_targets(void) { GList *entry; struct process *proc; GtkTreeIter iter; gchar *esctext; GdkPixbuf *icon; GtkTreePath *path = NULL; int preferred; /* Force the selection change to update the results */ force_results = 1; /* Add the "system" target */ gtk_list_store_append (GTK_LIST_STORE(targets_model), &iter); gtk_list_store_set (GTK_LIST_STORE(targets_model), &iter, COL_T_ICON, global_icon, COL_T_NAME, "Global", COL_T_MAX, "", COL_T_PROC, NULL, -1); /* Select it if it's our current target */ if (cur_target_pid == 0) path = gtk_tree_model_get_path(GTK_TREE_MODEL(targets_model), &iter); /* The core doesn't sort the list, we do here */ entry = g_list_sort(procs, compare_process); while(entry) { char targetstr[64]; char maxstr[32]; proc = entry->data; entry = g_list_next(entry); preferred = proc->name && prefered_process && strcmp(proc->name, prefered_process) == 0; /* Skip too small values */ if (!preferred && (proc->max * 0.001 < 0.1)) continue; if (preferred) gtk_list_store_insert(GTK_LIST_STORE(targets_model), &iter, 1); else gtk_list_store_append(GTK_LIST_STORE(targets_model), &iter); esctext = g_markup_escape_text(proc->name, -1); icon = proc->kernelthread ? kthread_icon : process_icon; sprintf(maxstr, "%.1f", proc->max * 0.001); targetstr[63] = 0; if (preferred) snprintf(targetstr, 63, "%s", esctext); else strncpy(targetstr, esctext, 63); gtk_list_store_set(GTK_LIST_STORE(targets_model), &iter, COL_T_ICON, icon, COL_T_NAME, targetstr, COL_T_MAX, maxstr, COL_T_PROC, proc, -1); if (cur_target_pid == proc->pid) path = gtk_tree_model_get_path(GTK_TREE_MODEL(targets_model), &iter); g_free(esctext); } if (path) gtk_tree_view_set_cursor(GTK_TREE_VIEW(targets_view), path, NULL, FALSE); } static void insert_results(GList *list) { GList *entry; struct latency_line *line; GtkTreeIter iter; gchar *reasonstr; int l; entry = g_list_first(list); while(entry) { char maxstr[32]; char percentstr[32]; line = entry->data; entry = g_list_next(entry); /* Skip too small values */ if (line->max * 0.001 < 0.1) continue; /* Remove crap \n at end of line */ reasonstr = g_strdup(line->reason); l = strlen(reasonstr); while(l) { if (reasonstr[--l] != '\n') break; reasonstr[l] = 0; } /* Store it all into the model */ gtk_list_store_append(GTK_LIST_STORE(results_model), &iter); sprintf(maxstr, "%.1f ms", line->max * 0.001); sprintf(percentstr, "%.1f %%", (line->time * 100 + 0.0001) / total_time); gtk_list_store_set(GTK_LIST_STORE(results_model), &iter, COL_R_CAUSE, reasonstr, COL_R_MAX, maxstr, COL_R_PERCENT, percentstr, COL_R_LINE, line, -1); g_free(reasonstr); } } static void insert_backtrace(struct latency_line *line) { GtkTreeIter iter; char *c = line->backtrace; char *c2; char buffer[1024]; while (c && *c) { while (*c == ' ') c++; if (!*c) break; c2 = strchr(c, ' '); if (c2) { int l = MIN(c2-c, 1023); strncpy(buffer, c, l); buffer[l] = 0; } else { strncpy(buffer, c, 1023); buffer[1023] = 0; } c = c2; gtk_list_store_append(GTK_LIST_STORE(backtrace_model), &iter); gtk_list_store_set(GTK_LIST_STORE(backtrace_model), &iter, COL_B_FUNC, buffer, -1); } gtk_tree_view_columns_autosize(GTK_TREE_VIEW(backtrace_view)); } static gint target_select(GtkTreeSelection *sel, void *data) { GtkTreeModel *model; GtkTreeIter iter; struct process *proc = NULL; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(targets_view)); if (gtk_tree_selection_get_selected(sel, &model, &iter)) gtk_tree_model_get(model, &iter, COL_T_PROC, &proc, -1); if (ignore_sel) return TRUE; if (proc && (force_results || proc->pid != cur_target_pid)) { cur_target_pid = proc->pid; remove_all_results(); insert_results(proc->latencies); } else if (!proc && (force_results || cur_target_pid != 0)) { cur_target_pid = 0; remove_all_results(); insert_results(lines); } /* We don't need to force updates anymore */ force_results = 0; return FALSE; } static gint backtrace_select(GtkTreeSelection *sel, void *data) { GtkTreeModel *model; GtkTreeIter iter; struct latency_line *line = NULL; sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(results_view)); if (gtk_tree_selection_get_selected(sel, &model, &iter)) gtk_tree_model_get(model, &iter, COL_R_LINE, &line, -1); if (ignore_sel) return TRUE; gtk_list_store_clear(backtrace_model); if (line) insert_backtrace(line); return TRUE; } static void do_refresh(void) { /* Ignore selection messages triggerd by the list during those updates */ ignore_sel = TRUE; /* Empty list views */ remove_all_targets(); remove_all_results(); /* Call core to update the glists */ update_list(); /* Stop ignoring selection changes */ ignore_sel = FALSE; /* Insert all targets again */ insert_all_targets(); /* Make them look good */ gtk_tree_view_columns_autosize(GTK_TREE_VIEW(targets_view)); gtk_tree_view_columns_autosize(GTK_TREE_VIEW(results_view)); } static void update_countdown(void) { char buffer[128]; sprintf(buffer, "Refresh in %d s", countdown); gtk_label_set_text(GTK_LABEL(countdown_label), buffer); } static gint timer_tick(void *data) { /* Maybe we should stop the timer instead .. oh well, Arjan will kill me :-) */ if (countdown_frozen) return TRUE; countdown--; if (countdown <= 0) { countdown = countdown_max; do_refresh(); } update_countdown(); return TRUE; } static void refresh_clicked(GtkButton *btn, void *data) { do_refresh(); countdown = countdown_max; update_countdown(); } static void freeze_toggled(GtkToggleButton *btn, void *data) { gboolean state = gtk_toggle_button_get_active(btn); countdown_frozen = state; } static GtkWidget *create_targets_list(void) { GtkWidget *scrollw; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *sel; /* We Create a scrolled window with a treeview to hold the target * list. Note that a lot of this is straight from the GTK tutorial :-) */ scrollw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); /* Create a tree view object */ targets_view = gtk_tree_view_new(); gtk_container_add(GTK_CONTAINER(scrollw), targets_view); /* We use a simple list store for 4 colums, one is not displayed */ targets_model = gtk_list_store_new(4, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); gtk_tree_view_set_model(GTK_TREE_VIEW(targets_view), GTK_TREE_MODEL(targets_model)); /* Create the column with icon & text */ column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, "Targets"); renderer = gtk_cell_renderer_pixbuf_new(); gtk_tree_view_column_pack_start(column, renderer, FALSE); gtk_tree_view_column_set_attributes(column, renderer, "pixbuf", COL_T_ICON, NULL); renderer = gtk_cell_renderer_text_new(); gtk_tree_view_column_pack_start(column, renderer, TRUE); gtk_tree_view_column_set_attributes(column, renderer, "markup", COL_T_NAME, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(targets_view), GTK_TREE_VIEW_COLUMN(column)); /* Add a column for the max latency */ renderer = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL); column = gtk_tree_view_column_new_with_attributes("Max", renderer, "text", COL_T_MAX, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(targets_view), GTK_TREE_VIEW_COLUMN(column)); /* Set selection mode to single */ sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(targets_view)); gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); /* Hookup selection changed message */ g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(target_select), NULL); return scrollw; } static GtkWidget *create_results_list(void) { GtkWidget *scrollw; GtkCellRenderer *cell; GtkTreeViewColumn *column; GtkTreeSelection *sel; /* We Create a scrolled window with a treeview to hold the target * list. Note that a lot of this is straight from the GTK tutorial :-) */ scrollw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrollw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); /* Create a tree view object */ results_view = gtk_tree_view_new(); gtk_container_add(GTK_CONTAINER(scrollw), results_view); /* We use a simple list store for 4 columns, one not visible */ results_model = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); gtk_tree_view_set_model(GTK_TREE_VIEW(results_view), GTK_TREE_MODEL(results_model)); /* Add columns */ cell = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Cause", cell, "text", COL_R_CAUSE, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(results_view), GTK_TREE_VIEW_COLUMN(column)); cell = gtk_cell_renderer_text_new (); g_object_set(G_OBJECT(cell), "xalign", 1.0, NULL); column = gtk_tree_view_column_new_with_attributes ("Maximum", cell, "text", COL_R_MAX, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(results_view), GTK_TREE_VIEW_COLUMN(column)); cell = gtk_cell_renderer_text_new (); g_object_set(G_OBJECT(cell), "xalign", 1.0, NULL); column = gtk_tree_view_column_new_with_attributes ("Percentage", cell, "text", COL_R_PERCENT, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(results_view), GTK_TREE_VIEW_COLUMN(column)); /* Set selection mode to single */ sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(results_view)); gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); /* Hookup selection changed message */ g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(backtrace_select), NULL); return scrollw; } static GtkWidget *create_backtrace_list(void) { GtkWidget *scrollw; GtkCellRenderer *renderer; GtkTreeViewColumn *column; GtkTreeSelection *sel; /* We Create a scrolled window with a treeview to hold the target * list. Note that a lot of this is straight from the GTK tutorial :-) */ scrollw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); /* Create a tree view object */ backtrace_view = gtk_tree_view_new(); gtk_container_add(GTK_CONTAINER(scrollw), backtrace_view); /* We use a simple list store */ backtrace_model = gtk_list_store_new(1, G_TYPE_STRING); gtk_tree_view_set_model(GTK_TREE_VIEW(backtrace_view), GTK_TREE_MODEL(backtrace_model)); /* Add columns */ renderer = gtk_cell_renderer_text_new (); column = gtk_tree_view_column_new_with_attributes ("Backtrace", renderer, "text", COL_B_FUNC, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(backtrace_view), GTK_TREE_VIEW_COLUMN(column)); /* Set selection mode to single */ sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(backtrace_view)); gtk_tree_selection_set_mode(sel, GTK_SELECTION_SINGLE); return scrollw; } static void create_targets_window(void) { GtkWidget *w, *paned, *paned2, *vbox, *hbox, *btn; /* We need a window first for the process list */ main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(main_window), "LatencyTOP "VERSION); g_signal_connect(G_OBJECT(main_window), "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_container_set_border_width(GTK_CONTAINER(main_window), 5); gtk_widget_set_size_request(main_window, 600, 400); /* Split top container vs. buttons etc... at the bottom */ vbox = gtk_vbox_new(FALSE, 5); gtk_container_add(GTK_CONTAINER(main_window), vbox); /* Split it in two with an hpaned */ paned = gtk_hpaned_new(); gtk_box_pack_start(GTK_BOX(vbox), paned, TRUE, TRUE, 0); /* Create the target list (left pane) */ w = create_targets_list(); gtk_paned_add1(GTK_PANED(paned), w); /* Split the right pane between results and backtrace */ paned2 = gtk_vpaned_new(); gtk_paned_add2(GTK_PANED(paned), paned2); /* Create the results list (right/top pane) */ w = create_results_list(); gtk_paned_add1(GTK_PANED(paned2), w); /* Create the backtrace list (right/bottom pane) */ w = create_backtrace_list(); gtk_paned_add2(GTK_PANED(paned2), w); /* The panner seems to default to a stupid position, I'm not sure * yet what's the right way of getting it to automagically adjust * to the size of the list items, so let's whack it for now to * some arbitrary value that looks better */ gtk_paned_set_position(GTK_PANED(paned), 200); gtk_paned_set_position(GTK_PANED(paned2), 250); /* Now create an hbox at the botton for various controls, etc... */ hbox = gtk_hbox_new(FALSE, 5); gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); /* Add the countdown */ countdown_label = gtk_label_new(""); gtk_box_pack_end(GTK_BOX(hbox), countdown_label, FALSE, FALSE, 0); btn = gtk_button_new_with_label("Refresh"); gtk_box_pack_end(GTK_BOX(hbox), btn, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(btn), "clicked", G_CALLBACK(refresh_clicked), NULL); freeze_button = gtk_toggle_button_new_with_label("Freeze"); gtk_box_pack_end(GTK_BOX(hbox), freeze_button, FALSE, FALSE, 0); g_signal_connect(G_OBJECT(freeze_button), "toggled", G_CALLBACK(freeze_toggled), NULL); } static load_icons(void) { GError *err; /* Hackish ... needs fixing obviously :-) * * We scale the icons to 18x18 because the ones I randomly grabbed * don't look good with my default font :-) Ideally, we should * get the font metrics yadada yadada... */ #define ICON_SIZE 18 #define PATH_PREFIX "/usr/share/latencytop/" err = NULL; global_icon = gdk_pixbuf_new_from_file_at_size(PATH_PREFIX "global.png", ICON_SIZE, ICON_SIZE, &err); if (!global_icon) { err = NULL; global_icon = gdk_pixbuf_new_from_file_at_size("global.png", ICON_SIZE, ICON_SIZE, &err); } err = NULL; kthread_icon = gdk_pixbuf_new_from_file_at_size(PATH_PREFIX "kernel_thread.png", ICON_SIZE, ICON_SIZE, &err); if (!kthread_icon) { err = NULL; kthread_icon = gdk_pixbuf_new_from_file_at_size("kernel_thread.png", ICON_SIZE, ICON_SIZE, &err); } err = NULL; process_icon = gdk_pixbuf_new_from_file_at_size(PATH_PREFIX "user_process.png", ICON_SIZE, ICON_SIZE, &err); if (!process_icon) { err = NULL; process_icon = gdk_pixbuf_new_from_file_at_size("user_process.png", ICON_SIZE, ICON_SIZE, &err); } } void start_gtk_ui(void) { load_icons(); create_targets_window(); /* Initialize the lists */ update_list(); insert_all_targets(); /* Make them look good */ gtk_tree_view_columns_autosize(GTK_TREE_VIEW(targets_view)); gtk_tree_view_columns_autosize(GTK_TREE_VIEW(results_view)); /* Show everything */ gtk_widget_show_all(main_window); /* Start the timer */ countdown = countdown_max; update_countdown(); g_timeout_add(1000, timer_tick, NULL); /* Run the main event loop */ gtk_main(); } int preinitialize_gtk_ui(int *argc, char ***argv) { int rc, i; rc = gtk_init_check(argc, argv); if (!rc) return FALSE; /* Hack... will do for now */ for (i = 1; i < *argc; i++) if (strcmp((*argv)[i], "--nogui") == 0) return FALSE; return TRUE; } latencytop-0.5ubuntu3/global.png0000664000000000000000000000431511175603262013732 0ustar PNG  IHDR szzgAMA abKGDV pHYs  ~tIME xJIDATxŗK\U>9=ݓL@B#p# 4"pF7.%U*wDKQ.@!<23==}\HZ{?{/qvwQwתKE=^sEb-oGS*d)֢aAktǎѣȕ'|_WL[EYo|یU(K>(8 p+(f}zuBs].3޽\yU]ۇ9wkÇMz0 Ҝ֍0"ԚD)rV-Vr X$>֘lQ6V^[z[o8J$oL/ŸKM?D"0Je\Mί[avJ'#!Q09߹(^}<'gq\m-J[THцBƣ2Z`R" ~$C*TOͼjj^k 8fTQ($.XkZkD6!Fk(RcH!Z_??{x_8V3ЍײڡP,b1ԸMk,#(2$RAi4JiVV+p\A?7-` @qضqusU7XVԸ7u>`b4O,kcPJF*EKr"H R:rFvcW8 ewq cE:t5VX6b12QJ֚g{mT[*@H'A.^ k$J!J#"\7YaQ?""$qBbqR b괻}[ ;K@ko~W,.r$88q0cҪ" $jt *eC|lnd) 2x5zʀ"Fu~LEDрAQB Kv$&i] Ѐ /OAkN '^'8$rl$V8H lZ)6O9p`y:F/I*@X'MX K]OG Vr+_EIEb Isvv~ R0[=MJ6:P3*y[ݎpZ7r!3q XcRkMbÐ_:$T9 bC{CSƨ8V] /Wṧr B LFT% $S‹ ,N`&z-Ux [?xuG=\i[j X`PID\aIz3,0v`77wxlftGn8Ir7X&(_祴T{ؖoc)SN`2Kq܋?71@"4IH|9ׇ:)e`0t>2NʂTd)ipSd䤺ȤoPR T`Az='9:C`܌* 4LզcA`8G^*4PpIENDB`latencytop-0.5ubuntu3/debian/0000775000000000000000000000000013260672050013201 5ustar latencytop-0.5ubuntu3/debian/rules0000775000000000000000000000042611542643662014273 0ustar #!/usr/bin/make -f include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/makefile.mk DEB_MAKE_CLEAN_TARGET = clean DEB_MAKE_BUILD_TARGET = latencytop DEB_MAKE_INSTALL_TARGET = install DESTDIR=$(CURDIR)/debian/latencytop DEB_MAKE_CHECK_TARGET = latencytop-0.5ubuntu3/debian/changelog0000664000000000000000000000330013260672050015047 0ustar latencytop (0.5ubuntu3) bionic; urgency=high * No change rebuild to pick up -fPIE compiler default -- Balint Reczey Tue, 03 Apr 2018 12:31:36 +0000 latencytop (0.5ubuntu2) xenial; urgency=medium * No-change rebuild for ncurses6 transition. -- Matthias Klose Sun, 07 Feb 2016 09:42:29 +0000 latencytop (0.5ubuntu1) natty; urgency=low * latencytop.8: - typo corrected (LP: #735262) -- Bhaveek Desai Mon, 21 Mar 2011 21:51:49 +0530 latencytop (0.5) unstable; urgency=low * New upstream version ( -- Giacomo Catenazzi Sun, 26 Jul 2009 13:06:24 +0200 latencytop (0.4) unstable; urgency=low * New upstream version (added block trace) * add options and keybinding to manpage (Closes: #476769) -- Giacomo Catenazzi Thu, 16 May 2008 08:23:03 +0200 latencytop (0.3-4) unstable; urgency=low * Ooops, finally merge all changes of previous versions. * Merging again some patches from git, so kernel support is enabled automatically at program start (Closes: #475548) * Don't clean up screen after writing errors (Closes: #469418) -- Giacomo Catenazzi Tue, 15 Apr 2008 08:08:15 +0200 latencytop (0.3-3) unstable; urgency=low * Fix building -- Giacomo Catenazzi Mon, 14 Apr 2008 09:05:34 +0200 latencytop (0.3-2) unstable; urgency=low * Put latencytop.trans in /usr/share/misc/ * Pull some patch from git. -- Giacomo Catenazzi Thu, 14 Feb 2008 19:12:26 +0100 latencytop (0.3-1) unstable; urgency=low * Initial release (Closes: #462184) -- Giacomo Catenazzi Tue, 12 Feb 2008 22:51:39 +0100 latencytop-0.5ubuntu3/debian/latencytop.manpages0000664000000000000000000000001511542643662017104 0ustar latencytop.8 latencytop-0.5ubuntu3/debian/watch0000664000000000000000000000046511542643662014247 0ustar # Example watch control file for uscan # Rename this file to "watch" and then you can run the "uscan" command # to check for upstream updates and more. # See uscan(1) for format # Compulsory line, this is a version 3 file version=3 http://www.latencytop.org/download.php download/latencytop-(.*)\.tar\.gz latencytop-0.5ubuntu3/debian/control0000664000000000000000000000141011542643751014607 0ustar Source: latencytop Section: utils Priority: extra Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Giacomo Catenazzi Build-Depends: cdbs, debhelper (>= 5), pkg-config, libncursesw5-dev, libglib2.0-dev, libgtk2.0-dev Standards-Version: 3.8.2 Homepage: http://www.latencytop.org/ Package: latencytop Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: A tool for developers to visualize system latencies LatencyTOP is a Linux tool for software developers (both kernel and userspace), aimed at identifying where in the system latency is happening, and what kind of operation/action is causing the latency to happen so that the code can be changed to avoid the worst latency hiccups. latencytop-0.5ubuntu3/debian/compat0000664000000000000000000000000211542643662014407 0ustar 5 latencytop-0.5ubuntu3/debian/copyright0000664000000000000000000000133211542643662015143 0ustar This package was debianized by Giacomo A. Catenazzi on Tue, 12 Feb 2008 22:36:39 +0100. It was downloaded from http://www.latencytop.org/ Upstream Author: Arjan van de Ven Copyright: Copyright 2007, Intel Corporation Copyright 2008, Intel Corporation Copyright 2008, Benjamin Herrenschmidt License: This program file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. The Debian packaging is (C) 2008, Giacomo A. Catenazzi and is licensed under the GPL-2, see `/usr/share/common-licenses/GPL-2'. latencytop-0.5ubuntu3/debian/README.Debian0000664000000000000000000000050011542643662015245 0ustar latencytop for Debian --------------------- To use latencytop, you need a kernel 2.6.25 (or newer), configured with CONFIG_LATENCYTOP ( Kernel hacking -> Latency measuring infrastructure ). Further documentation is in http://www.latencytop.org/ -- Giacomo Catenazzi Tue, 12 Feb 2008 22:36:39 +0100 latencytop-0.5ubuntu3/debian/latencytop.dirs0000664000000000000000000000003611542643662016255 0ustar usr/sbin usr/share/latencytop latencytop-0.5ubuntu3/latencytop.c0000664000000000000000000002764011175603262014320 0ustar /* * Copyright 2008, Intel Corporation * * This file is part of LatencyTOP * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this program in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * Authors: * Arjan van de Ven */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "latencytop.h" GList *lines; GList *procs; GList *allprocs; int total_time = 0; int total_count = 0; unsigned int pid_with_max = 0; unsigned int pidmax = 0; int firsttime = 1; int noui; int dump_unknown; char *prefered_process; static void add_to_global(struct latency_line *line) { GList *item; struct latency_line *line2; item = g_list_first(lines); while (item) { line2 = item->data; item = g_list_next(item); if (strcmp(line->reason, line2->reason)==0) { line2->count += line->count; line2->time += line->time; if (line->max > line2->max) line2->max = line->max; free(line); return; } } lines = g_list_append(lines, line); } static void add_to_process(struct process *process, struct latency_line *line) { GList *item; struct latency_line *line2; item = g_list_first(process->latencies); while (item) { line2 = item->data; item = g_list_next(item); if (strcmp(line->reason, line2->reason)==0) { line2->count += line->count; line2->time += line->time; if (line->max > line2->max) line2->max = line->max; free(line); return; } } process->latencies = g_list_append(process->latencies, line); } static void fixup_reason(struct latency_line *line, char *c) { char *c2; c2 = strchr(c, '\n'); if (c2) *c2=0; while (c[0]==' ') c++; strncpy(line->backtrace, c, 4096); c2 = translate(c); if (c2 == NULL) { line->reason[0] = '['; strncpy(line->reason + 1, c, 1022); for (c2 = line->reason + 1; *c2 && (c2 - line->reason) < 1022; c2++) if (*c2 == ' ') break; *(c2++) = ']'; *(c2++) = 0; } else strncpy(line->reason, c2, 1024); } void parse_global_list(void) { FILE *file; char *ln; size_t dummy; file = fopen("/proc/latency_stats","r+"); if (!file) { fprintf(stderr, "Please enable the CONFIG_LATENCYTOP configuration in your kernel.\n"); fprintf(stderr, "Exiting...\n"); exit(EXIT_FAILURE); } /* wipe first line */ ln = NULL; if (getline(&ln, &dummy, file) < 0) { free(ln); fclose(file); return; } free(ln); total_time = 0; total_count = 0; while (!feof(file)) { struct latency_line *line; char *c; ln = NULL; if (getline(&ln, &dummy, file) < 0) { free(ln); break; } if (strlen(ln)<2) { free(ln); break; } line = malloc(sizeof(struct latency_line)); memset(line, 0, sizeof(struct latency_line)); line->count = strtoull(ln, &c, 10); line->time = strtoull(c, &c, 10); line->max = strtoull(c, &c, 10); total_time += line->time; total_count += line->count; fixup_reason(line, c); add_to_global(line); free(ln); ln = NULL; } /* reset for next time */ fprintf(file, "erase\n"); fclose(file); } gint comparef(gconstpointer A, gconstpointer B) { struct latency_line *a, *b; a = (struct latency_line *)A; b = (struct latency_line *)B; if (a->max > b->max) return -1; if (a->max < b->max) return 1; if (a->time > b->time) return -1; if (a->time < b->time) return 1; return -1; } void sort_list(void) { GList *entry; struct latency_line *line; total_time = 0; lines = g_list_sort(lines, comparef); entry = g_list_first(lines); while (entry) { line = entry->data; entry = g_list_next(entry); total_time = total_time + line->time; } } void delete_list(void) { GList *entry, *entry2,*next; struct latency_line *line; struct process *proc; while (lines) { entry = g_list_first(lines); line = entry->data; free(line); lines = g_list_delete_link(lines, entry); } entry = g_list_first(allprocs); while (entry) { next = g_list_next(entry); proc = entry->data; while (proc->latencies) { entry2 = g_list_first(proc->latencies); line = entry2->data; free(line); proc->latencies = g_list_delete_link(proc->latencies, entry2); } proc->max = 0; if (!proc->exists) { free(proc); allprocs = g_list_delete_link(allprocs, entry); } entry = next; } g_list_free(procs); procs = NULL; } void prune_unused_procs(void) { GList *entry, *entry2; struct latency_line *line; struct process *proc; entry = g_list_first(procs); while (entry) { proc = entry->data; entry2 = g_list_next(entry); if (!proc->used) { while (proc->latencies) { entry2 = g_list_first(proc->latencies); line = entry2->data; free(line); proc->latencies = g_list_delete_link(proc->latencies, entry2); } free(proc); procs = g_list_delete_link(procs, entry); } entry = entry2; } } void parse_process(struct process *process) { DIR *dir; struct dirent *dirent; char filename[PATH_MAX]; sprintf(filename, "/proc/%i/task/", process->pid); dir = opendir(filename); if (!dir) return; while ((dirent = readdir(dir))) { FILE *file; char *line = NULL; size_t dummy; int pid; if (dirent->d_name[0]=='.') continue; pid = strtoull(dirent->d_name, NULL, 10); if (pid<=0) /* not a process */ continue; sprintf(filename, "/proc/%i/task/%i/latency", process->pid, pid); file = fopen(filename, "r+"); if (!file) continue; /* wipe first line*/ if (getline(&line, &dummy, file) < 0) { free(line); continue; } free(line); while (!feof(file)) { struct latency_line *ln; char *c, *c2; line = NULL; if (getline(&line, &dummy, file) < 0) { free(line); break; } if (strlen(line)<2) { free(line); break; } ln = malloc(sizeof(struct latency_line)); memset(ln, 0, sizeof(struct latency_line)); ln->count = strtoull(line, &c, 10); ln->time = strtoull(c, &c, 10); ln->max = strtoull(c, &c, 10); fixup_reason(ln, c); if (ln->max > process->max) process->max = ln->max; add_to_process(process, ln); process->used = 1; free(line); line = NULL; } /* reset for next time */ fprintf(file, "erase\n"); fclose(file); } /* 100 usec minimum */ if (!firsttime) { struct latency_line *ln, *ln2; ln = malloc(sizeof(struct latency_line)); ln2 = malloc(sizeof(struct latency_line)); memset(ln, 0, sizeof(struct latency_line)); if (process->delaycount) ln->count = process->delaycount; else ln->count = 1; if (process->totaldelay > 0.00001) ln->time = process->totaldelay * 1000; else ln->time = process->maxdelay * 1000; ln->max = process->maxdelay * 1000; strcpy(ln->reason, "Scheduler: waiting for cpu"); if (ln->max > process->max) process->max = ln->max; memcpy(ln2, ln, sizeof(struct latency_line)); add_to_process(process, ln); add_to_global(ln2); process->used = 1; } closedir(dir); } struct process* find_create_process(unsigned int pid) { GList *entry; struct process *proc; entry = g_list_first(allprocs); while (entry) { proc = entry->data; if (proc->pid == pid) { return proc; } entry = g_list_next(entry); } proc = malloc(sizeof(struct process)); memset(proc, 0, sizeof(struct process)); proc->pid = pid; allprocs = g_list_append(allprocs, proc); return proc; } void parse_processes(void) { DIR *dir; struct dirent *dirent; char filename[PATH_MAX]; struct process *process; pidmax = 0; dir = opendir("/proc"); if (!dir) return; while ((dirent = readdir(dir))) { FILE *file; char *line; size_t dummy; int pid; if (dirent->d_name[0]=='.') continue; pid = strtoull(dirent->d_name, NULL, 10); if (pid<=0) /* not a process */ continue; process = find_create_process(pid); process->exists = 1; sprintf(filename, "/proc/%i/status", pid); file = fopen(filename, "r"); if (file) { char *q; line = NULL; if (getline(&line, &dummy, file) >= 0) { strncpy(&process->name[0], &line[6], 64); q = strchr(process->name, '\n'); if (q) *q=0; fclose(file); } free(line); line = NULL; } if (process->name && prefered_process && strcmp(process->name, prefered_process)==0) { pid_with_max = pid; pidmax = INT_MAX; } sprintf(filename, "/proc/%i/sched", pid); file = fopen(filename, "r+"); if (file) { char *q; double d; while (!feof(file)) { line = NULL; if (getline(&line, &dummy, file) < 0) { free(line); break; } q = strchr(line, ':'); if (strstr(line, "se.wait_max") && q) { sscanf(q+1,"%lf", &d); process->maxdelay = d; } if (strstr(line, "se.wait_sum") && q) { sscanf(q+1,"%lf", &d); process->totaldelay = d; } if (strstr(line, "se.wait_count") && q) { sscanf(q+1,"%lf", &d); process->delaycount = d; } free(line); line = NULL; } fprintf(file,"erase"); fclose(file); } sprintf(filename, "/proc/%i/statm", pid); file = fopen(filename, "r"); if (file) { line = NULL; if (getline(&line, &dummy, file) >= 0) { if (strcmp(line, "0 0 0 0 0 0 0\n")==0) process->kernelthread = 1; } fclose(file); free(line); line = NULL; } parse_process(process); if (process->latencies) { process->latencies = g_list_sort(process->latencies, comparef); if (!process->kernelthread && pidmax < process->max) { pidmax = process->max; pid_with_max = process->pid; } procs = g_list_append(procs, process); }; } closedir(dir); } void dump_global_to_console(void) { GList *item; struct latency_line *line; int i = 0; item = g_list_first(lines); while (item) { line = item->data; item = g_list_next(item); printf( "[max %4.1fmsec] %40s - %5.2f msec (%3.1f%%)\n", line->max * 0.001, line->reason, (line->time * 0.001 +0.0001) / line->count, line->time * 100.0 / total_time ); i++; } } static void enable_sysctl(void) { FILE *file; file = fopen("/proc/sys/kernel/latencytop", "w"); if (!file) return; fprintf(file, "1"); fclose(file); } static void disable_sysctl(void) { FILE *file; file = fopen("/proc/sys/kernel/latencytop", "w"); if (!file) return; fprintf(file, "0"); fclose(file); } void update_list(void) { delete_list(); parse_processes(); prune_unused_procs(); parse_global_list(); sort_list(); if (!total_time) total_time = 1; firsttime = 0; } static void cleanup_sysctl(void) { disable_sysctl(); disable_fsync_tracer(); } int main(int argc, char **argv) { int i, use_gtk = 0; enable_sysctl(); enable_fsync_tracer(); atexit(cleanup_sysctl); #ifdef HAS_GTK_GUI if (preinitialize_gtk_ui(&argc, &argv)) use_gtk = 1; #endif if (!use_gtk) preinitialize_text_ui(&argc, &argv); for (i = 1; i < argc; i++) if (strcmp(argv[i],"-d") == 0) { init_translations("latencytop.trans"); parse_global_list(); sort_list(); dump_global_to_console(); return EXIT_SUCCESS; } for (i = 1; i < argc; i++) if (strcmp(argv[i], "--unknown") == 0) { noui = 1; dump_unknown = 1; } /* Allow you to specify a process name to track */ for (i = 1; i < argc; i++) if (argv[i][0] != '-') { prefered_process = strdup(argv[i]); break; } init_translations("/usr/share/latencytop/latencytop.trans"); if (!translations) init_translations("latencytop.trans"); /* for those who don't do make install */ while (noui) { sleep(5); fprintf(stderr, "."); } #ifdef HAS_GTK_GUI if (use_gtk) start_gtk_ui(); else #endif start_text_ui(); prune_unused_procs(); delete_list(); return EXIT_SUCCESS; } latencytop-0.5ubuntu3/translate.c0000664000000000000000000000532611175603262014130 0ustar /* * Copyright 2007, Intel Corporation * * This file is part of LatencyTOP * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this program in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * Authors: * Arjan van de Ven */ #define _GNU_SOURCE #include #include #include #include #include #include #include "latencytop.h" /* translate kernel output to human readable */ struct translate_line { int priority; char function[200]; char display[200]; }; GList *translations; char *translate(char *line) { char buffer[4096], *c, *c2; int prio = 0; char *selected = NULL; GList *item; struct translate_line *trans; memset(buffer, 0, 4096); strncpy(buffer, line, 4096); c2 = buffer; while (c2[0] == ' ') c2++; while (c2 && strlen(c2) > 0) { c = strchr(c2, ' '); if (c) *c = 0; item = g_list_first(translations); while (item) { trans = item->data; item = g_list_next(item); if (trans->priority >= prio && strcmp(trans->function, c2)==0) { selected = trans->display; prio = trans->priority; } } if (c) c2 = c+1; else c2 = NULL; } if (dump_unknown && prio < 2) { FILE *file; file = fopen("latencytop.log", "w+"); if (file) { fprintf(file, "%s\n", line); fclose(file); } printf("Unknown: %s\n", line); } return selected; } void init_translations(char *filename) { char *c, *c2; FILE *file; file = fopen(filename, "r"); if (!file) return; while (!feof(file)) { struct translate_line *trans; size_t dummy; char *line = NULL; if (getline(&line, &dummy, file) <= 0) { free(line); break; } if (line[0]=='#') { free(line); continue; } trans = malloc(sizeof(struct translate_line)); memset(trans, 0, sizeof(trans)); c2 = line; c = strchr(c2, '\t'); if (c) { *c = 0; trans->priority = strtoull(c2, NULL, 10); c2 = c+1; } c = strchr(c2, '\t'); if (c) { *c = 0; strcpy(trans->function, c2); c2 = c+1; } while (*c2=='\t') c2++; strcpy(trans->display, c2); translations = g_list_append(translations, trans); free(line); } fclose(file); } latencytop-0.5ubuntu3/user_process.png0000664000000000000000000000527311175603262015212 0ustar PNG  IHDR00WbKGD pHYs  ~tIME (B HIDATxݙk?w:;y%%l|SpI(4@^])BB_H!1i^E (Tjɧ+I;;;;w` ;;kyǛ6fQ9&x @+Vdn_0I5MvA=Ir$}[3}oXidu'VΥj9GrK~K}~ʌ%&dZ9\Ӛs34b[j=Ť9Mpf،sX"G&J%{θK5Biewr :gK*APJ$IfUՀ2G &jwW|M*Qrݓ8Z3>KεFCP!GGg߿ T:U?4bl:@F)¥Q =`lt XOd ,Uj|M뼸< .E=2$5!txuU677J"G)%zfIÁ v$i֛LFe3XbOxo33]?Lj Ϸ@g͛7Y 9a!p#Yք Фۙ+Zhd"J#Ds  wlp<tj }||67}J/m:V wTn:RI^YO?EkM:#F0f698m@U&d 2l%; 8ԕ̮;o(oBd8[bWb :q]?lYiwCzW{Vzܺu Ygy&RLk_6 .AGfB69}ܦqa0SDj8sq5@s ܼm] m&(-Q`0`ee%7N`7pdfz} -A ಾ̽{9#1EYـ%L@TEg0p8$'l [[[尪dL1,vI.d7ėRF#u[)if3 ~T1C\ʣO^fI{MmVzlW{logR tt3WqWng}Iyd}D)n !=K-P'|C {{߽{" ,PVQ1j$2a{߷ /1q9a3Jbsj/6AiU v]߰7]V=M)oPՉ\ mڍ6T%_(c]r6)8%= 4\$y/"Ӈ~@u.awQM%,R:]-".)&{mF*mt#m,"%oZiʅq‰˵FivWAA08.NC]666Jt;H:iK K|Ϲm֐DP^%P̓s5"O'N%1OܳR[?} 5ZkU;i S;x߿Ln ѱ&4jmH,v*B8;+L@)j"ITp4:jy3rvg7_~fJ0>J TqThhmmGcOp6gnj P [8$uNF'<HmFmKIGs*c(_l>jC#cNT6stk?oB4t׎EBCrYb9LSC(s>#mKD)6򬴜:do "n\k4f|^2J15"6C4ZED@?GFcܹyGW5`18Q8Rִ8nuM8R ?3Ǒ!`%o̐;X&L]ݟl!s7(6nrX ݺӚPD+9߬-;?VRQm'vHHcKQ insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME latencytop \- a tool for developers to visualize system latencies .SH SYNOPSIS .B latencytop .RI [ --unknown ] " " [ processes ... ] .SH DESCRIPTION This manual page documents briefly the .B latencytop command. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBlatencytop\fP is a Linux* tool for software developers (both kernel and userspace), aimed at identifying where in the system latency is happening, and what kind of operation/action is causing the latency to happen so that the code can be changed to avoid the worst latency hiccups. .PP \fBLatencyTOP\fP focuses on the cases where the applications want to run and execute useful code, but there's some resource that's not currently available (and the kernel then blocks the process). This is done both on a system level and on a per process level, so that you can see what's happening to the system, and which process is suffering and/or causing the delays. You can walk the processes by using the cursor keys. If you press \fBs\fP followed by a letter, then only active processes starting with that letter are displayed and walked. If you press \fBs\fP followed by \fB0\fP then that filter is reset. If you press \fBf\fP then \fBLatencyTop\fP displays a list of all processes currently waiting for an \fBfsync\fP to finish. Pressing \fBf\fP again returns you to the normal operating mode of \fBLatencyTop\fP. .SH SEE ALSO .BR powertop (1) .br The program is more fully described at http://www.latencytop.org .SH AUTHOR latencytop was written by Arjan van de Ven . .PP This manual page was written by Giacomo Catenazzi , for the Debian project (but may be used by others). latencytop-0.5ubuntu3/latencytop.h0000664000000000000000000000236611175603314014321 0ustar #define VERSION "0.5" struct latency_line; struct latency_line { char reason[1024]; char backtrace[4096]; int count; double time; double max; }; struct process { unsigned int pid; int kernelthread; char name[64]; unsigned int max; GList *latencies; int used; int exists; /* scheduler stats */ double maxdelay; double totaldelay; int delaycount; }; extern GList *lines; extern GList *procs; extern GList *translations; extern int total_time; extern int total_count; extern unsigned int pid_with_max; extern unsigned int pidmax; extern int noui; extern int dump_unknown; extern char *prefered_process; #define PT_COLOR_DEFAULT 1 #define PT_COLOR_HEADER_BAR 2 #define PT_COLOR_ERROR 3 #define PT_COLOR_RED 4 #define PT_COLOR_YELLOW 5 #define PT_COLOR_GREEN 6 #define PT_COLOR_BRIGHT 7 extern int preinitialize_gtk_ui(int *argc, char ***argv); extern void start_gtk_ui(void); extern void preinitialize_text_ui(int *argc, char ***argv); extern void start_text_ui(void); extern char *translate(char *line); extern void init_translations(char *filename); extern int fsync_display(int duration); extern int enable_fsync_tracer(void); extern int disable_fsync_tracer(void); extern void update_list(void); latencytop-0.5ubuntu3/Makefile0000664000000000000000000000224011542643662013425 0ustar # FIXME: Use autoconf ? HAS_GTK_GUI = 1 DESTDIR = SBINDIR = /usr/sbin XCFLAGS = -W -g `pkg-config --cflags glib-2.0` -D_FORTIFY_SOURCE=2 -Wno-sign-compare -I/usr/include/ncursesw LDF = -Wl,--as-needed `pkg-config --libs glib-2.0` -lncursesw OBJS= latencytop.o text_display.o translate.o fsync.o ifdef HAS_GTK_GUI XCFLAGS += `pkg-config --cflags gtk+-2.0` -DHAS_GTK_GUI LDF += `pkg-config --libs gtk+-2.0` OBJS += gtk_display.o endif # # The w in -lncursesw is not a typo; it is the wide-character version # of the ncurses library, needed for multi-byte character languages # such as Japanese and Chinese etc. # # On Debian/Ubuntu distros, this can be found in the # libncursesw5-dev package. # # We write explicity this "implicit rule" %.o : %.c gcc -c $(CFLAGS) $(XCFLAGS) $< -o $@ latencytop: $(OBJS) latencytop.h Makefile gcc $(CFLAGS) $(OBJS) $(LDF) -o latencytop clean: rm -f *~ latencytop DEADJOE *.o install: latencytop mkdir -p $(DESTDIR)/usr/share/latencytop install -m 0644 latencytop.trans $(DESTDIR)/usr/share/latencytop/latencytop.trans install -m 0644 *.png $(DESTDIR)/usr/share/latencytop/ install -m 0755 latencytop $(DESTDIR)$(SBINDIR)/ latencytop-0.5ubuntu3/text_display.c0000664000000000000000000002246411175603262014646 0ustar /* * Copyright 2008, Intel Corporation * * This file is part of LatencyTOP * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this program in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * Authors: * Arjan van de Ven */ #include #include #include #include #include #include #include #include #include #include #include #include #include "latencytop.h" static WINDOW *title_bar_window; static WINDOW *global_window; static WINDOW *process_window; static WINDOW *right_window; static GList *cursor_e = NULL; static void cleanup_curses(void) { endwin(); } static void zap_windows(void) { if (title_bar_window) { delwin(title_bar_window); title_bar_window = NULL; } if (global_window) { delwin(global_window); global_window = NULL; } if (process_window) { delwin(process_window); process_window = NULL; } if (right_window) { delwin(right_window); right_window = NULL; } } static int maxx, maxy; static void setup_windows(void) { int midy; getmaxyx(stdscr, maxy, maxx); zap_windows(); midy = (maxy+4)/2; title_bar_window = subwin(stdscr, 1, maxx, 0, 0); global_window = subwin(stdscr, midy-4 , maxx, 2, 0); process_window = subwin(stdscr, 1, maxx, maxy-1, 0); right_window = subwin(stdscr, (maxy-midy-3), maxx, midy, 0); werase(stdscr); refresh(); } static void show_title_bar(void) { wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); werase(title_bar_window); mvwprintw(title_bar_window, 0, 0, " LatencyTOP version "VERSION" (C) 2008 Intel Corporation"); wrefresh(title_bar_window); } static void print_global_list(void) { GList *item; struct latency_line *line; int i = 1; mvwprintw(global_window, 0, 0, "Cause"); mvwprintw(global_window, 0, 50, " Maximum Percentage\n"); item = g_list_first(lines); while (item && i < 10) { line = item->data; item = g_list_next(item); if (line->max*0.001 < 0.1) continue; mvwprintw(global_window, i, 0, "%s", line->reason); mvwprintw(global_window, i, 50, "%5.1f msec %5.1f %%\n", line->max * 0.001, (line->time * 100 +0.0001) / total_time); i++; } wrefresh(global_window); } static void display_process_list(unsigned int cursor_pid, char filter) { GList *entry, *start = NULL; struct process *proc; int i = 0, xpos = 0; char startswith; entry = procs; retry: werase(process_window); xpos = 0; start = cursor_e; if (!start) { start = g_list_first(procs); cursor_e = start; } if (!start) return; proc = start->data; while (proc->pid > cursor_pid && cursor_pid > 0) { start = g_list_previous(start); proc = start->data; cursor_e = start; } /* and print 7 */ i = 0; while (start) { proc = start->data; startswith = proc->name[0]; startswith = toupper(startswith); if ((filter != '\0') && (startswith != filter)) { start = g_list_next(start); continue; } if (proc->pid == cursor_pid) { if (xpos + strlen(proc->name) + 2 > maxx && cursor_e) { cursor_e = g_list_next(cursor_e); goto retry; } wattron(process_window, A_REVERSE); } if (xpos + strlen(proc->name) + 2 <= maxx) mvwprintw(process_window, 0, xpos, " %s ", proc->name); xpos += strlen(proc->name)+2; wattroff(process_window, A_REVERSE); start = g_list_next(start); i++; } wrefresh(process_window); } static int one_pid_back(unsigned int cursor_pid, char filter) { GList *entry, *start = NULL; struct process *proc; char startswith; entry = procs; while (entry) { proc = entry->data; if (proc->pid == cursor_pid) { start = entry; break; } entry = g_list_next(entry); } while (start) { if (g_list_previous(start)) start = g_list_previous(start); if (start) { proc=start->data; startswith = proc->name[0]; startswith = toupper (startswith); if ((filter == '\0') || (startswith == filter)) return proc->pid; else start = g_list_previous(start); } } return 0; } static int one_pid_forward(unsigned int cursor_pid, char filter) { GList *entry, *start = NULL; struct process *proc; char startswith; entry = procs; while (entry) { proc = entry->data; if (proc->pid == cursor_pid) { start = entry; break; } entry = g_list_next(entry); } while (start) { if (g_list_next(start)) start = g_list_next(start); if (start) { proc=start->data; startswith = proc->name[0]; startswith = toupper (startswith); if ((filter == '\0') || (startswith == filter)) return proc->pid; else start = g_list_next(start); } } return 0; } static void print_process(unsigned int pid) { struct process *proc; GList *item; werase(right_window); double total = 0.0; item = g_list_first(procs); while (item) { char header[4096]; int i = 0; GList *item2; struct latency_line *line; proc = item->data; item = g_list_next(item); if (proc->pid != pid) continue; wattron(right_window, A_REVERSE); sprintf(header, "Process %s (%i) ", proc->name, proc->pid); while (strlen(header) < maxx) strcat(header, " "); mvwprintw(right_window, 0, 0, "%s", header); item2 = g_list_first(proc->latencies); while (item2 && i < 6) { line = item2->data; item2 = g_list_next(item2); total = total + line->time; } mvwprintw(right_window, 0, 43, "Total: %5.1f msec", total*0.001); wattroff(right_window, A_REVERSE); item2 = g_list_first(proc->latencies); while (item2 && i < 6) { line = item2->data; item2 = g_list_next(item2); if (line->max*0.001 < 0.1) continue; mvwprintw(right_window, i+1, 0, "%s", line->reason); mvwprintw(right_window, i+1, 50, "%5.1f msec %5.1f %%", line->max * 0.001, (line->time * 100 +0.0001) / total ); i++; } } wrefresh(right_window); } static int done_yet(int time, struct timeval *p1) { int seconds; int usecs; struct timeval p2; gettimeofday(&p2, NULL); seconds = p2.tv_sec - p1->tv_sec; usecs = p2.tv_usec - p1->tv_usec; usecs += seconds * 1000000; if (usecs > time * 1000000) return 1; return 0; } static int update_display(int duration, char *filterchar) { struct timeval start,end,now; int key; int repaint = 1; fd_set rfds; gettimeofday(&start, NULL); setup_windows(); show_title_bar(); print_global_list(); while (!done_yet(duration, &start)) { if (repaint) { display_process_list(pid_with_max, *filterchar); print_process(pid_with_max); } FD_ZERO(&rfds); FD_SET(0, &rfds); gettimeofday(&now, NULL); end.tv_sec = start.tv_sec + duration - now.tv_sec; end.tv_usec = start.tv_usec - now.tv_usec; while (end.tv_usec < 0) { end.tv_sec --; end.tv_usec += 1000000; }; key = select(1, &rfds, NULL, NULL, &end); repaint = 1; if (key) { char keychar; keychar = fgetc(stdin); if (keychar == 27) { keychar = fgetc(stdin); if (keychar==79) keychar = fgetc(stdin); } keychar = toupper(keychar); if (keychar == 'Z' || keychar == 'A' || keychar == 'D') pid_with_max = one_pid_back(pid_with_max, *filterchar); if (keychar == 'X' || keychar == 'B' || keychar == 'C') pid_with_max = one_pid_forward(pid_with_max, *filterchar); if (keychar == 'Q') return 0; if (keychar == 'R') { cursor_e = NULL; return 1; } if (keychar == 'S') { keychar = fgetc(stdin); if (keychar == 27) { keychar = fgetc(stdin); if (keychar==79) keychar = fgetc(stdin); } keychar = toupper (keychar); if (keychar >= 'A' && keychar <= 'Z') *filterchar = keychar; else if (keychar == '0') *filterchar = '\0'; } if (keychar == 'F') { endwin(); if (!fsync_display(duration)) return 0; setup_windows(); show_title_bar(); } if (keychar < 32) repaint = 0; } } cursor_e = NULL; return 1; } void preinitialize_text_ui(int *argc, char ***argv) { } void start_text_ui(void) { char filterchar = '\0'; int ret = 1; initscr(); start_color(); keypad(stdscr, TRUE); /* enable keyboard mapping */ nonl(); /* tell curses not to do NL->CR/NL on output */ cbreak(); /* take input chars one at a time, no wait for \n */ noecho(); /* dont echo input */ curs_set(0); /* turn off cursor */ use_default_colors(); init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK); init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE); init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED); init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED); init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW); init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN); init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK); atexit(cleanup_curses); while (ret) { update_list(); ret = update_display(30, &filterchar); } } latencytop-0.5ubuntu3/kernel_thread.png0000664000000000000000000000711311175603262015300 0ustar PNG  IHDR00WgAMA1_IDATx՚kluwf%ZJDZzPr)P'zXR"-\C?EE$Тhm]hNjDZ-lzXbDJKKIQcwfwvf9N/b'ag >0a@\JP3MA&7W ^ؠ>j (Zh"_WT4x^VsWC )aP>ħФFX5\"޽H`@dՔ VWR4)zBYm*5>J@C"D[qQ=W k" @ 24tq8ۡi 6Ck&vMl)%nŐiIL {BTM[,/27W{'7=@uBQuw&_>˻_deb6rr1:*Hi tiM*,/[9`0p+ gΞih{έ ??S^y,27?}2FL"Z~EkK `/0}d :s L~܎d3i2jx>νJxHRd2T+WM-"m@l.2F%d d3ӳy"3,YK`R}e6)S !@QǩHǹqeaѽw'GqLL["D m@Goc+ 1::JXDutt䯠:\7$(®]p]aEaϞ=l޼1Ҧd\E ]PR#JHzG=j3 ;\1P4L7u(ZEGGǏD8y$U ڑ/'_7p J?&5ojm[ڵUWmp,~ "'!W¤i80krB@wwwRtxM6-YBu[TmcgwDGXUrwj"\Q]R^D7VBA P6bS3S+(O0 ,kqIgijS+Vi癜hmpȃ<ôբz2H$ꢿ^I[k ][W6*`B4)@fmƘy!T) v^|I:2t7fQYcj5 t,r!S_m˲BrOA,䱬*8%&&ڃ2^4U_yl8L|Xm۱4Z M6rHR笈w}Y1ՐT8Q|Mx5qMG*uW!X}^{zRPUUQU\&TGu*i!kw&6ro&ҒR R.$&֢`f@*ZqEQ@PD$aYőnť;Z`Ҟر?xdx:沉a[47l24,UGq~Wf~1}Yx\.c&]x<NR]gCW;6<fV,.H&aj;< )Ouy뭷xz OiR( Wb2M{_4ꅅSl_nϟ(DEUjM +iTz- H199 /_fllFcZ"ꉮt-}/?\@޷CRW^׷*kkf1BE!"D``avoPU˲re0(%Ii!%+I/eI`+3VZ&Lx +DO*dkG_6ַo-sچ68 m}cRaiBF m.mٶlAk+T*sK?8y\r =xUI *\jңobMA5߷=6/ɥ^x:X68v 6(Hk{H={OۮȒ(xnb8bF]xdL+{eW OJqg{(-e/S&@ ncx#x@-R >L=Ш7qh끝VΘϵ@E+Xa ؜hUBu_(*gAgDr7@BA317ԝ'O#lM!l??V04χPIENDB`latencytop-0.5ubuntu3/fsync.c0000664000000000000000000001741411175603262013256 0ustar /* * Copyright 2008, Intel Corporation * * This file is part of LatencyTOP * * This program file is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; version 2 of the License. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this program in a file named COPYING; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA * * Authors: * Arjan van de Ven */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "latencytop.h" struct fsync_process { char name[PATH_MAX]; int fsync_count; GList *files; }; struct fsync_files { char name[PATH_MAX]; int fsync_count; }; static GList *fsync_data; static chain_file(struct fsync_process *proc, char *filename) { struct fsync_files *file; GList *item; proc->fsync_count++; item = proc->files; while (item) { file = item->data; item = g_list_next(item); if (strcmp(file->name, filename)==0) { file->fsync_count++; return; } } file = malloc(sizeof(struct fsync_files)); if (!file) return; memset(file, 0, sizeof(struct fsync_files)); strncpy(file->name, filename, PATH_MAX-1); file->fsync_count = 1; proc->files = g_list_append(proc->files, file); } static report_file(char *process, char *file) { struct fsync_process *proc; GList *item; item = fsync_data; while (item) { proc = item->data; item = g_list_next(item); if (strcmp(proc->name, process) == 0) { chain_file(proc, file); return; } } proc = malloc(sizeof(struct fsync_process)); if (!proc) return; memset(proc, 0, sizeof(struct fsync_process)); strncpy(proc->name, process, PATH_MAX-1); chain_file(proc, file); fsync_data = g_list_append(fsync_data, proc); } static gint sort_files(gconstpointer A, gconstpointer B) { struct fsync_files *a = (struct fsync_files *)A; struct fsync_files *b = (struct fsync_files *)B; return a->fsync_count < b->fsync_count; } static gint sort_process(gconstpointer A, gconstpointer B) { struct fsync_process *a = (struct fsync_process *)A; struct fsync_process *b = (struct fsync_process *)B; return a->fsync_count < b->fsync_count; } static void sort_the_lot(void) { GList *item; struct fsync_process *proc; item = fsync_data = g_list_sort(fsync_data, sort_process); while (item) { proc = item->data; item = g_list_next(item); proc->files = g_list_sort(proc->files, sort_files); } } static void write_to_file(char *filename, char *value) { FILE *file; file = fopen(filename, "w"); if (!file) return; fprintf(file,"%s\n", value); fclose(file); } int enable_fsync_tracer(void) { int ret; /* * Steps to do: * * mount -t debugfs none /sys/kernel/debug/ * cd /sys/kernel/debug/tracing * echo fsync > current_tracer * echo ftrace_printk > iter_ctrl * echo 1 > tracing_enabled */ ret = system("/bin/mount -t debugfs none /sys/kernel/debug/"); if (!ret) return -1; write_to_file("/sys/kernel/debug/tracing/current_tracer", "fsync"); write_to_file("/sys/kernel/debug/tracing/iter_ctrl", "ftrace_printk"); write_to_file("/sys/kernel/debug/tracing/tracing_enabled", "1"); } int disable_fsync_tracer(void) { write_to_file("/sys/kernel/debug/tracing/tracing_enabled", "0"); } static WINDOW *title_bar_window; static WINDOW *global_window; static void fsync_cleanup_curses(void) { endwin(); } static void zap_windows(void) { if (title_bar_window) { delwin(title_bar_window); title_bar_window = NULL; } if (global_window) { delwin(global_window); global_window = NULL; } } static int maxx, maxy; static void fsync_setup_windows(void) { int midy; getmaxyx(stdscr, maxy, maxx); zap_windows(); title_bar_window = subwin(stdscr, 1, maxx, 0, 0); global_window = subwin(stdscr, maxy-3 , maxx, 2, 0); werase(stdscr); refresh(); } #if 0 /* Dead code */ static void fsync_initialize_curses(void) { if (noui) return; initscr(); start_color(); keypad(stdscr, TRUE); /* enable keyboard mapping */ nonl(); /* tell curses not to do NL->CR/NL on output */ cbreak(); /* take input chars one at a time, no wait for \n */ noecho(); /* dont echo input */ curs_set(0); /* turn off cursor */ use_default_colors(); init_pair(PT_COLOR_DEFAULT, COLOR_WHITE, COLOR_BLACK); init_pair(PT_COLOR_HEADER_BAR, COLOR_BLACK, COLOR_WHITE); init_pair(PT_COLOR_ERROR, COLOR_BLACK, COLOR_RED); init_pair(PT_COLOR_RED, COLOR_WHITE, COLOR_RED); init_pair(PT_COLOR_YELLOW, COLOR_WHITE, COLOR_YELLOW); init_pair(PT_COLOR_GREEN, COLOR_WHITE, COLOR_GREEN); init_pair(PT_COLOR_BRIGHT, COLOR_WHITE, COLOR_BLACK); atexit(cleanup_curses); } #endif static void show_title_bar(void) { wattrset(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); wbkgd(title_bar_window, COLOR_PAIR(PT_COLOR_HEADER_BAR)); werase(title_bar_window); mvwprintw(title_bar_window, 0, 0, " LatencyTOP -- fsync() view... type 'F' to exit"); wrefresh(title_bar_window); } static void print_global_list(void) { GList *item, *item2; struct fsync_process *proc; struct fsync_files *file; int i = 1, i2 = 0; int y = 1; werase(global_window); mvwprintw(global_window, 0, 0, "Process File"); item = g_list_first(fsync_data); while (item && i < maxy-6) { proc = item->data; item = g_list_next(item); mvwprintw(global_window, y, 0, "%s (%i)", proc->name, proc->fsync_count); y++; item2 = proc->files; while (item2 && i2 < 5) { file = item2->data; item2 = g_list_next(item2); mvwprintw(global_window, y, 10, "%s (%i)", file->name, file->fsync_count); y++; i2++; } i++; y++; } wrefresh(global_window); } static void parse_ftrace(void) { FILE *file; char line[PATH_MAX]; file = fopen("/sys/kernel/debug/tracing/trace", "r"); if (!file) return; while (!feof(file)) { char *c, *c2; memset(line, 0, PATH_MAX); fgets(line, PATH_MAX-1, file); c = strchr(line, '\n'); if (c) *c = 0; c = strstr(line, "probe_do_fsync: Process "); if (!c) continue; c += 24; c2 = strchr(c, ' '); if (!c2) continue; *c2 = 0; c2++; c2 = strstr(c2, "fsync on "); if (!c2) continue; c2 += 9; report_file(c, c2); } fclose(file); sort_the_lot(); } int fsync_display(int duration) { struct timeval start,end,now; int key; fd_set rfds; int curduration; fsync_setup_windows(); show_title_bar(); curduration = 3; if (curduration > duration) curduration = duration; parse_ftrace(); print_global_list(); while (1) { FD_ZERO(&rfds); FD_SET(0, &rfds); gettimeofday(&start, NULL); gettimeofday(&now, NULL); end.tv_sec = start.tv_sec + curduration - now.tv_sec; end.tv_usec = start.tv_usec - now.tv_usec; while (end.tv_usec < 0) { end.tv_sec --; end.tv_usec += 1000000; }; curduration = duration; if (curduration > 5) curduration = 5; /* clear the ftrace buffer */ write_to_file("/sys/kernel/debug/tracing/tracing_enabled", "0"); write_to_file("/sys/kernel/debug/tracing/tracing_enabled", "1"); key = select(1, &rfds, NULL, NULL, &end); parse_ftrace(); print_global_list(); if (key) { char keychar; keychar = fgetc(stdin); if (keychar == 27) { keychar = fgetc(stdin); if (keychar==79) keychar = fgetc(stdin); } keychar = toupper(keychar); if (keychar == 'F') { fsync_cleanup_curses(); return 1; } if (keychar == 'Q') { fsync_cleanup_curses(); return 0; } } } return 1; }