diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2010-06-10 17:53:51 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2010-06-10 17:53:51 -0400 |
| commit | 3c95290d3fb593145b8ce1163d795a08f05e112c (patch) | |
| tree | e6fc1bea660993e4eaaf5b716bef577d6fbf692e | |
| parent | d01b699fffc573e7653e00d608444735c04f9dca (diff) | |
| parent | b09e5f4f3fc5c8fc2c51376050af19660c8053f4 (diff) | |
Merge branch 'kernelshark-devel' into trace-cmd
Conflicts:
Makefile
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
60 files changed, 3865 insertions, 491 deletions
diff --git a/Documentation/HTML/images/kshark-cursor-1.png b/Documentation/HTML/images/kshark-cursor-1.png new file mode 100644 index 0000000..64d19be --- /dev/null +++ b/Documentation/HTML/images/kshark-cursor-1.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-filter-advance-1.png b/Documentation/HTML/images/kshark-filter-advance-1.png new file mode 100644 index 0000000..23f6584 --- /dev/null +++ b/Documentation/HTML/images/kshark-filter-advance-1.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-filter-del-adv.png b/Documentation/HTML/images/kshark-filter-del-adv.png new file mode 100644 index 0000000..88e2376 --- /dev/null +++ b/Documentation/HTML/images/kshark-filter-del-adv.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-filter-event-adv-list.png b/Documentation/HTML/images/kshark-filter-event-adv-list.png new file mode 100644 index 0000000..c2f2d52 --- /dev/null +++ b/Documentation/HTML/images/kshark-filter-event-adv-list.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-filter-events-sched.png b/Documentation/HTML/images/kshark-filter-events-sched.png new file mode 100644 index 0000000..0941317 --- /dev/null +++ b/Documentation/HTML/images/kshark-filter-events-sched.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-filter-events.png b/Documentation/HTML/images/kshark-filter-events.png new file mode 100644 index 0000000..4732f8a --- /dev/null +++ b/Documentation/HTML/images/kshark-filter-events.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-filter-list-adv-irq.png b/Documentation/HTML/images/kshark-filter-list-adv-irq.png new file mode 100644 index 0000000..0b04031 --- /dev/null +++ b/Documentation/HTML/images/kshark-filter-list-adv-irq.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-filter-sync-graph-1.png b/Documentation/HTML/images/kshark-filter-sync-graph-1.png new file mode 100644 index 0000000..82e5849 --- /dev/null +++ b/Documentation/HTML/images/kshark-filter-sync-graph-1.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-filter-task-menu.png b/Documentation/HTML/images/kshark-filter-task-menu.png new file mode 100644 index 0000000..77fb98a --- /dev/null +++ b/Documentation/HTML/images/kshark-filter-task-menu.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-filter.png b/Documentation/HTML/images/kshark-filter.png new file mode 100644 index 0000000..0e9a380 --- /dev/null +++ b/Documentation/HTML/images/kshark-filter.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-graph-info-line.png b/Documentation/HTML/images/kshark-graph-info-line.png new file mode 100644 index 0000000..4f6be47 --- /dev/null +++ b/Documentation/HTML/images/kshark-graph-info-line.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-graph-plot-area.png b/Documentation/HTML/images/kshark-graph-plot-area.png new file mode 100644 index 0000000..84ed90e --- /dev/null +++ b/Documentation/HTML/images/kshark-graph-plot-area.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-graph-plot-title.png b/Documentation/HTML/images/kshark-graph-plot-title.png new file mode 100644 index 0000000..cbb8d2d --- /dev/null +++ b/Documentation/HTML/images/kshark-graph-plot-title.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-list-adjust.png b/Documentation/HTML/images/kshark-list-adjust.png new file mode 100644 index 0000000..aff15c1 --- /dev/null +++ b/Documentation/HTML/images/kshark-list-adjust.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-list-enable-filter-1.png b/Documentation/HTML/images/kshark-list-enable-filter-1.png new file mode 100644 index 0000000..8321c92 --- /dev/null +++ b/Documentation/HTML/images/kshark-list-enable-filter-1.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-list-graph-follow-1.png b/Documentation/HTML/images/kshark-list-graph-follow-1.png new file mode 100644 index 0000000..c4f8702 --- /dev/null +++ b/Documentation/HTML/images/kshark-list-graph-follow-1.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-list-graph-follow-2.png b/Documentation/HTML/images/kshark-list-graph-follow-2.png new file mode 100644 index 0000000..451de10 --- /dev/null +++ b/Documentation/HTML/images/kshark-list-graph-follow-2.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-list-info-area.png b/Documentation/HTML/images/kshark-list-info-area.png new file mode 100644 index 0000000..394dfdd --- /dev/null +++ b/Documentation/HTML/images/kshark-list-info-area.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-open.png b/Documentation/HTML/images/kshark-open.png new file mode 100644 index 0000000..1b201ce --- /dev/null +++ b/Documentation/HTML/images/kshark-open.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-plot-cpu-1.png b/Documentation/HTML/images/kshark-plot-cpu-1.png new file mode 100644 index 0000000..f49de93 --- /dev/null +++ b/Documentation/HTML/images/kshark-plot-cpu-1.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-plot-cpu-2.png b/Documentation/HTML/images/kshark-plot-cpu-2.png new file mode 100644 index 0000000..c1ea7d1 --- /dev/null +++ b/Documentation/HTML/images/kshark-plot-cpu-2.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-plot-cpu-result.png b/Documentation/HTML/images/kshark-plot-cpu-result.png new file mode 100644 index 0000000..635ddda --- /dev/null +++ b/Documentation/HTML/images/kshark-plot-cpu-result.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-plot-menu.png b/Documentation/HTML/images/kshark-plot-menu.png new file mode 100644 index 0000000..a26f052 --- /dev/null +++ b/Documentation/HTML/images/kshark-plot-menu.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-plot-task-measure-preempt.png b/Documentation/HTML/images/kshark-plot-task-measure-preempt.png new file mode 100644 index 0000000..243aef1 --- /dev/null +++ b/Documentation/HTML/images/kshark-plot-task-measure-preempt.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-plot-task-measure.png b/Documentation/HTML/images/kshark-plot-task-measure.png new file mode 100644 index 0000000..d4b7149 --- /dev/null +++ b/Documentation/HTML/images/kshark-plot-task-measure.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-plot-task-result.png b/Documentation/HTML/images/kshark-plot-task-result.png new file mode 100644 index 0000000..12bbf8b --- /dev/null +++ b/Documentation/HTML/images/kshark-plot-task-result.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-plot-task-select.png b/Documentation/HTML/images/kshark-plot-task-select.png new file mode 100644 index 0000000..be7f365 --- /dev/null +++ b/Documentation/HTML/images/kshark-plot-task-select.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-plot-task-zoom-1.png b/Documentation/HTML/images/kshark-plot-task-zoom-1.png new file mode 100644 index 0000000..716b5c6 --- /dev/null +++ b/Documentation/HTML/images/kshark-plot-task-zoom-1.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-select-a-1.png b/Documentation/HTML/images/kshark-select-a-1.png new file mode 100644 index 0000000..40a6cfa --- /dev/null +++ b/Documentation/HTML/images/kshark-select-a-1.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-select-b-1.png b/Documentation/HTML/images/kshark-select-b-1.png new file mode 100644 index 0000000..df4df41 --- /dev/null +++ b/Documentation/HTML/images/kshark-select-b-1.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-zoom-in-2.png b/Documentation/HTML/images/kshark-zoom-in-2.png new file mode 100644 index 0000000..25235e5 --- /dev/null +++ b/Documentation/HTML/images/kshark-zoom-in-2.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-zoom-in-3.png b/Documentation/HTML/images/kshark-zoom-in-3.png new file mode 100644 index 0000000..2c55319 --- /dev/null +++ b/Documentation/HTML/images/kshark-zoom-in-3.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-zoom-in-select.png b/Documentation/HTML/images/kshark-zoom-in-select.png new file mode 100644 index 0000000..12c2be7 --- /dev/null +++ b/Documentation/HTML/images/kshark-zoom-in-select.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/images/kshark-zoom-out-select.png b/Documentation/HTML/images/kshark-zoom-out-select.png new file mode 100644 index 0000000..25c7cfe --- /dev/null +++ b/Documentation/HTML/images/kshark-zoom-out-select.png | |||
| Binary files differ | |||
diff --git a/Documentation/HTML/index.html b/Documentation/HTML/index.html new file mode 100644 index 0000000..12c9957 --- /dev/null +++ b/Documentation/HTML/index.html | |||
| @@ -0,0 +1,653 @@ | |||
| 1 | <html> | ||
| 2 | |||
| 3 | <title>KernelShark</title> | ||
| 4 | |||
| 5 | <body> | ||
| 6 | |||
| 7 | <h1>KernelShark</h1> | ||
| 8 | |||
| 9 | <hr><h1><a name="ToC">Table of Contents</a></h1> | ||
| 10 | <p><b><a name="ToC_1" href="#Introduction">Introduction</a></b></br> | ||
| 11 | <p><b><a name="ToC_2" href="#graph">The Graph View</a></b></br> | ||
| 12 | <menu> | ||
| 13 | <li><a name="ToC_2_1" href="#graph-zoom-in">Zooming In</a> | ||
| 14 | <li><a name="ToC_2_2" href="#graph-zoom-out">Zooming Out</a> | ||
| 15 | <li><a name="ToC_2_3" href="#graph-marker">Graph Markers</a> | ||
| 16 | <li><a name="ToC_2_4" href="#graph-cursor">Graph Cursor</a> | ||
| 17 | <li><a name="ToC_2_5" href="#graph-plots">Graph Plots</a> | ||
| 18 | <menu> | ||
| 19 | <li><a name="ToC_2_5_1" href="#graph-plot-task">Task Plots</a> | ||
| 20 | <li><a name="ToC_2_5_2" href="#graph-plot-cpu">CPU Plots</a> | ||
| 21 | </menu> | ||
| 22 | </menu> | ||
| 23 | <p><b><a name="ToC_3" href="#list">The List View</a></b></br> | ||
| 24 | <menu> | ||
| 25 | <li><a name="ToC_3_1" href="#list-select">Selecting an event</a> | ||
| 26 | <li><a name="ToC_3_2" href="#list-graph-toggle">Graph follows toggle</a> | ||
| 27 | </menu> | ||
| 28 | <p><b><a name="ToC_4" href="#filters">Filters</a></b></br> | ||
| 29 | <menu> | ||
| 30 | <li><a name="ToC_4_1" href="#filter-task">Task Filter</a> | ||
| 31 | <li><a name="ToC_4_2" href="#filter-event">Event Filter</a> | ||
| 32 | <menu> | ||
| 33 | <li><a name="ToC_4_2_1" href="#filter-adv-event">Advance Event Filter</a> | ||
| 34 | </menu> | ||
| 35 | </menu> | ||
| 36 | |||
| 37 | |||
| 38 | <h1><a name="Introduction">Introduction</a></h1> | ||
| 39 | |||
| 40 | <p> | ||
| 41 | KernelShark is a front end reader of <b>trace-cmd(1)</b> output. "trace-cmd record" | ||
| 42 | and "trace-cmd extract" create a trace.dat (<b>trace-cmd.dat(5)</b>) file. | ||
| 43 | <b>kernelshark</b> can read this file and produce a graph and list view of its data. | ||
| 44 | </p> | ||
| 45 | |||
| 46 | <img src="images/kshark-open.png"> | ||
| 47 | |||
| 48 | <p> | ||
| 49 | The application has two main viewing areas split by a paned divider. The top half | ||
| 50 | is a graphical display of the data and the bottom half is a list view of each | ||
| 51 | event. Underneath the menu bar is the graph information area: | ||
| 52 | </p> | ||
| 53 | |||
| 54 | <h4><a name="graph-info-line">Graph Info Area</a></h4> | ||
| 55 | |||
| 56 | <img src="images/kshark-graph-info-line.png"> | ||
| 57 | |||
| 58 | <p> | ||
| 59 | The graph information line displays the timestamp of various locations. | ||
| 60 | The Pointer: shows the timestamp of where the mouse pointer is. The Cursor: is | ||
| 61 | the timestamp of the cursor location. To select a cursor location, double click | ||
| 62 | on the graph. Marker A is set with a left mouse click and Marker B is set | ||
| 63 | with a with a left mouse click while holding down the shift key. | ||
| 64 | </p> | ||
| 65 | |||
| 66 | <p> | ||
| 67 | The graph is broken into two parts, the plot title section: | ||
| 68 | </p> | ||
| 69 | |||
| 70 | <h4><a name="graph-plot-title">Plot Title</a></h4> | ||
| 71 | |||
| 72 | <img src="images/kshark-graph-plot-title.png"> | ||
| 73 | |||
| 74 | <p> | ||
| 75 | and the plot area: | ||
| 76 | </p> | ||
| 77 | |||
| 78 | <img src="images/kshark-graph-plot-area.png"> | ||
| 79 | |||
| 80 | <p> | ||
| 81 | The plot area contains the data of the given plot, where plots can be per CPU or | ||
| 82 | per task. The top of the plot area shows a timeline. The numbers in the timeline | ||
| 83 | are seconds. The time in the timeline is taken from the timestamps within | ||
| 84 | the trace.dat file which are architecture dependent. The time usually is the timestamp | ||
| 85 | from when the system started. | ||
| 86 | </p> | ||
| 87 | |||
| 88 | <p> | ||
| 89 | Below the graph is the list area. | ||
| 90 | </p> | ||
| 91 | |||
| 92 | <h4><a name="list-area">List Area</a></h4> | ||
| 93 | |||
| 94 | <img src="images/kshark-list-info-area.png"> | ||
| 95 | |||
| 96 | <p> | ||
| 97 | The list area contains the Page of the list. The list can hold a maximum of | ||
| 98 | 1 million entries per page. If the trace data contains more than a million | ||
| 99 | entries, then the list will have more than one page. | ||
| 100 | </p> | ||
| 101 | |||
| 102 | <p> | ||
| 103 | The list area also contains a search field to search for elements in the | ||
| 104 | list. | ||
| 105 | </p> | ||
| 106 | |||
| 107 | <h1><a name="graph">The Graph View</a></h1> | ||
| 108 | |||
| 109 | <p> | ||
| 110 | The graph view of kernelshark shows graphical plots of the data stored in | ||
| 111 | the trace.dat file. The data plots are per CPU or per task. | ||
| 112 | When there are too many events within the resolution of the graph, | ||
| 113 | the plots will appear as a rainbow colored bar. To make more sense out of | ||
| 114 | the graphs, you need to zoom into a given location to see the details of | ||
| 115 | that time frame more clearly. | ||
| 116 | </p> | ||
| 117 | |||
| 118 | <h2><a name="graph-zoom-in">Zooming In</a></h2> | ||
| 119 | |||
| 120 | <p> | ||
| 121 | To zoom in, left mouse click and hold and then drag the mouse right, release | ||
| 122 | to zoom. When you click the left mouse button a line will appear and stay | ||
| 123 | at that location. When you move the mouse to the right, another line appears | ||
| 124 | and will follow the mouse. When you release the mouse button, the area | ||
| 125 | between the two lines become the new width of the screen. That is, the graph | ||
| 126 | zooms in until the lines match the width of the screen. This allows you to | ||
| 127 | zoom into a specific location. | ||
| 128 | </p> | ||
| 129 | |||
| 130 | <img src="images/kshark-zoom-in-select.png"> | ||
| 131 | |||
| 132 | <p> | ||
| 133 | The area that you selected will now become the new width of the viewable area. | ||
| 134 | The smaller the selection, the deeper the zoom. Note, that you must select 10 | ||
| 135 | pixels to zoom in. Less than 10 pixels will cancel the zoom. You can continue zooming | ||
| 136 | in until you get more details. | ||
| 137 | </p> | ||
| 138 | |||
| 139 | <img src="images/kshark-zoom-in-3.png"> | ||
| 140 | |||
| 141 | <p> | ||
| 142 | To save on resources, when zooming in, the beginning | ||
| 143 | and end of the full trace may not be reachable with the horizontal scroll bar. | ||
| 144 | If a plot contains no events within the reachable area, then the line will be empty, | ||
| 145 | as CPU 1 is in the above image. | ||
| 146 | </p> | ||
| 147 | |||
| 148 | <p> | ||
| 149 | CPU 0 shows two tasks that were running. One task | ||
| 150 | is given a pink/red color and the other a green color. The think colored | ||
| 151 | horizontal bar represents a task other than idle was running. The small | ||
| 152 | lines that jet out of the bar are where events occur. | ||
| 153 | </p> | ||
| 154 | |||
| 155 | <p> | ||
| 156 | If you zoom in enough such that a single event has enough room between itself | ||
| 157 | and other events, the type of event and the name and PID of the task that was running will appear | ||
| 158 | over the event. | ||
| 159 | </p> | ||
| 160 | |||
| 161 | <h2><a name="graph-zoom-out">Zooming Out</a></h2> | ||
| 162 | |||
| 163 | <p> | ||
| 164 | To zoom back out, left mouse click and hold and then drag the mouse left. | ||
| 165 | This time the width between the two lines will become a single pixel. | ||
| 166 | The farther apart the lines are, the farther the zoom out will be. | ||
| 167 | Zoom out will stop at the width of the full trace. | ||
| 168 | </p> | ||
| 169 | |||
| 170 | <img src="images/kshark-zoom-out-select.png"> | ||
| 171 | |||
| 172 | <p> | ||
| 173 | When the mouse is over an event, a tool tip will appear showing the event name, | ||
| 174 | the <a href="#latency">latency data</a>, the event info, the timestamp and the task | ||
| 175 | name and task process ID. | ||
| 176 | </p> | ||
| 177 | |||
| 178 | <img src="images/kshark-zoom-in-2.png"> | ||
| 179 | |||
| 180 | <h2><a name="graph-marker">Graph Markers</a></h2> | ||
| 181 | |||
| 182 | <p> | ||
| 183 | There are two markers that can be placed on the graph as well as a cursor. | ||
| 184 | Marker A is set by a left mouse click. When a marker is set, the | ||
| 185 | <a href="#graph-info-line">graph info area</a> will be updated. | ||
| 186 | Marker A is represented by a green line: | ||
| 187 | </p> | ||
| 188 | |||
| 189 | <img src="images/kshark-select-a-1.png"> | ||
| 190 | |||
| 191 | <p> | ||
| 192 | To set Marker B, press and hold the shift key and click the left mouse button. | ||
| 193 | Marker B will show up in red. | ||
| 194 | </p> | ||
| 195 | |||
| 196 | <img src="images/kshark-select-b-1.png"> | ||
| 197 | |||
| 198 | <p> | ||
| 199 | When both the A and B markers are set, the <a href="#graph-info-line">graph info area</a> | ||
| 200 | will show the timestamp of where the A and B markers are, as well as the difference | ||
| 201 | between the two. All timestamps are in seconds, with a resolution of microseconds. | ||
| 202 | </p> | ||
| 203 | |||
| 204 | <h2><a name="graph-cursor">Graph Cursor</a></h2> | ||
| 205 | |||
| 206 | <p> | ||
| 207 | Double clicking on the graph will set the cursor. The cursor is a blue line, and when | ||
| 208 | it is set, it will also select the event in the list view that is the closest event at the | ||
| 209 | timeline of where the cursor was selected. | ||
| 210 | </p> | ||
| 211 | |||
| 212 | <img src="images/kshark-cursor-1.png"> | ||
| 213 | |||
| 214 | <p> | ||
| 215 | The above shows that list item 217448 (sys_exit) was the closest event to where | ||
| 216 | the cursor was selected. | ||
| 217 | </p> | ||
| 218 | |||
| 219 | <p> | ||
| 220 | Note that setting the cursor with double click will also set Marker A. | ||
| 221 | </p> | ||
| 222 | |||
| 223 | <h2><a name="graph-plots">Graph Plots</a></h2> | ||
| 224 | |||
| 225 | <p> | ||
| 226 | The graph data is represented by plots. The data on the plots is either CPU specific or | ||
| 227 | task specific. If it is CPU specific, then the data is the timeline of events that | ||
| 228 | happened on a given CPU (which CPU is shown in the <a href="#graph-plot-title">plot title area</a>). | ||
| 229 | If the plot is task specific, then the timeline of events is for the given | ||
| 230 | task regardless of what CPU it was on at the time. The task name is also shown | ||
| 231 | in the plot title area. | ||
| 232 | </p> | ||
| 233 | |||
| 234 | <p> | ||
| 235 | By default, all the CPUs within the loaded trace.dat file are plotted. | ||
| 236 | There are two ways to plot a task. One way is to right mouse click over a | ||
| 237 | displayed task in the graph and select the plot option. This will add the | ||
| 238 | task plot directly underneath the CPU plot that the task was on where | ||
| 239 | the right mouse click took place. The other way is to use the Plots menu. | ||
| 240 | </p> | ||
| 241 | |||
| 242 | <img src="images/kshark-plot-menu.png"> | ||
| 243 | |||
| 244 | <h3><a name="graph-plot-task">Task Plots</a></h3> | ||
| 245 | |||
| 246 | <p> | ||
| 247 | Selecting the "Tasks" menu item will bring up a dialog with all the tasks | ||
| 248 | that were found in the trace data. | ||
| 249 | </p> | ||
| 250 | |||
| 251 | <img src="images/kshark-plot-task-select.png"> | ||
| 252 | |||
| 253 | <p> | ||
| 254 | Selecting a task in this dialog will add the task plot to the bottom of the graph | ||
| 255 | area. Unselecting a task in this dialog will remove the plot. | ||
| 256 | </p> | ||
| 257 | |||
| 258 | <img src="images/kshark-plot-task-result.png"> | ||
| 259 | |||
| 260 | <p> | ||
| 261 | The colors in the task plots are different depending on which CPU the task | ||
| 262 | was on at the time. The CPU plots change colors as different tasks run | ||
| 263 | on the CPU, and the task plots change color depending on what CPU the task | ||
| 264 | is running on. This makes it easy to see how much a task | ||
| 265 | bounces around the CPUs. Zooming in on a task plot also shows some more | ||
| 266 | characteristics of the task. | ||
| 267 | </p> | ||
| 268 | |||
| 269 | <img src="images/kshark-plot-task-zoom-1.png"> | ||
| 270 | |||
| 271 | <p> | ||
| 272 | The hollow green bar that is shown in front of some events in the task | ||
| 273 | plot represents when the task was woken up from a sleeping state to | ||
| 274 | when it actually ran. The hollow red bar between some events shows that | ||
| 275 | the task was preempted by another task even though that task | ||
| 276 | was still runnable. | ||
| 277 | </p> | ||
| 278 | |||
| 279 | <p> | ||
| 280 | Since the hollow green bar shows the wake up latency of the task, the | ||
| 281 | <a href="#graph-marker">A,B markers</a> can be used to measure that time. | ||
| 282 | </p> | ||
| 283 | |||
| 284 | <img src="images/kshark-plot-task-measure.png"> | ||
| 285 | |||
| 286 | <p> | ||
| 287 | The above shows that the epiphany-browser with PID 28072 had a 479 microsecond wake up | ||
| 288 | latency. The same can be done with the preemption latency. | ||
| 289 | </p> | ||
| 290 | |||
| 291 | <img src="images/kshark-plot-task-measure-preempt.png"> | ||
| 292 | |||
| 293 | <h3><a name="graph-plot-cpu">CPU Plots</a></h3> | ||
| 294 | |||
| 295 | <p> | ||
| 296 | Selecting the "CPUs" plot menu item pops up a dialog that shows the available CPUs that | ||
| 297 | can be plotted. | ||
| 298 | <p> | ||
| 299 | |||
| 300 | <img src="images/kshark-plot-cpu-1.png"> | ||
| 301 | |||
| 302 | <p> | ||
| 303 | Removing a selected CPU and hitting "Apply" will remove that CPU plot. | ||
| 304 | </p> | ||
| 305 | |||
| 306 | <img src="images/kshark-plot-cpu-2.png"> | ||
| 307 | |||
| 308 | <p> | ||
| 309 | |||
| 310 | <img src="images/kshark-plot-cpu-result.png"> | ||
| 311 | |||
| 312 | <h1><a name="list">The List View</a></h1> | ||
| 313 | |||
| 314 | <p> | ||
| 315 | The list view is in the bottom half paned window and can be expanded or shortened | ||
| 316 | with the paned handle. | ||
| 317 | </p> | ||
| 318 | |||
| 319 | <img src="images/kshark-list-adjust.png"> | ||
| 320 | |||
| 321 | <p> | ||
| 322 | The top of the list view contains the <a href="#list-area">list area</a> which has the list page, list | ||
| 323 | search, and "graph follows" toggle button. If more than a million events are stored in the | ||
| 324 | list, then each set of million will be on a different page. | ||
| 325 | </p> | ||
| 326 | |||
| 327 | <p> | ||
| 328 | The columns of the list are: | ||
| 329 | </p> | ||
| 330 | |||
| 331 | <ul> | ||
| 332 | <li><b>#</b> - the index into the list. | ||
| 333 | <li><b>CPU</b> - the CPU that the event occurred on. | ||
| 334 | <li><b>Time Stamp</b> - The timestamp of the event. This is in seconds with microsecond | ||
| 335 | resolution. | ||
| 336 | <li><b>PID</b> - The process ID of the task that was running when the event occurred. | ||
| 337 | <li><b><a name="latency">Latency</a></b> - The latency is broken into 5 fields: | ||
| 338 | <ol> | ||
| 339 | <li>Interrupts disabled - 'd' if interrupts are disabled, otherwise '.' | ||
| 340 | <li>Need reschedule - 'N' if the kernel was notified that a schedule is needed, otherwise '.' | ||
| 341 | <li>In IRQ - 'h' if in a hard IRQ (hardware triggered), 's' if in a soft IRQ | ||
| 342 | (context where the kernel initiated a the IRQ handler) or if soft IRQs | ||
| 343 | are disabled, 'H' if in a hard IRQ and soft IRQs are disabled or the hard IRQ | ||
| 344 | triggered while processing a soft IRQ, otherwise '.' | ||
| 345 | <li>Preemption counter - The index of the preemption counter. If it is other | ||
| 346 | than zero, then the kernel will not preempt the running tasks, even | ||
| 347 | if a schedule has been requested by some event. If the counter is zero, | ||
| 348 | then '.' is shown. | ||
| 349 | <li>Lock depth - The depth of the big kernel lock being held. The big kernel | ||
| 350 | lock is recursive (same task may acquire it multiple times). On the first | ||
| 351 | acquisition, the depth is zero. This field will be zero or greater, or | ||
| 352 | '.' if the big kernel lock is not held. When the big kernel lock is | ||
| 353 | finally removed from the kernel, this field will go away as well. | ||
| 354 | </ol> | ||
| 355 | <li><b>Event</b> - The name of the event. | ||
| 356 | <li><b>Info</b> - The data output of a particular event. | ||
| 357 | </ul> | ||
| 358 | |||
| 359 | <p> | ||
| 360 | The list search can find an event based on the contents in a row. Select a column, a | ||
| 361 | match criteria and the content to match to find the next row that matches the | ||
| 362 | search. The match criterion is one of the following: | ||
| 363 | </p> | ||
| 364 | |||
| 365 | <ul> | ||
| 366 | <li><b>contains</b> - the row cell of the selected column contains the match data. This works with numbers | ||
| 367 | as well. | ||
| 368 | <li><b>full match</b> - the row cell of the selected column matches exactly the match data. | ||
| 369 | <li><b>does not have</b> - the row cell of the selected column does not contain the match data. | ||
| 370 | </ul> | ||
| 371 | |||
| 372 | <p> | ||
| 373 | The search will find the next event that has the matching data within the column. | ||
| 374 | </p> | ||
| 375 | |||
| 376 | <h2><a name="list-select">Selecting an event</a></h2> | ||
| 377 | <p> | ||
| 378 | A single click on a row will select the row, but a double click on a row will select | ||
| 379 | that row as well as set the graph cursor to the location of that event. If the plot | ||
| 380 | that the event is on is not visible then the graph will adjust its vertical view area | ||
| 381 | to show the plot with the selected event. This has no effect on | ||
| 382 | <a href="#graph-marker">graph markers</a>. | ||
| 383 | <p> | ||
| 384 | |||
| 385 | <h2><a name="list-graph-toggle">Graph follows toggle</a></h2> | ||
| 386 | |||
| 387 | <p> | ||
| 388 | When the "graph follows" toggle is set, then even a single click on a row | ||
| 389 | will move the graph cursor. With the mouse focus on the list, using the keyboard | ||
| 390 | up and down arrow keys will move the selection of the list as well as the graph | ||
| 391 | cursor. | ||
| 392 | </p> | ||
| 393 | |||
| 394 | <img src="images/kshark-list-graph-follow-1.png"> | ||
| 395 | <p> | ||
| 396 | <img src="images/kshark-list-graph-follow-2.png"> | ||
| 397 | |||
| 398 | <h1><a name="filters">Filters</a></h1> | ||
| 399 | |||
| 400 | <p> | ||
| 401 | The amount of data that can be stored in a trace.dat file can be enormous. | ||
| 402 | To make any sense out of some traces, it may be required to only display various | ||
| 403 | events. The same can be true about tasks. | ||
| 404 | Kernelshark has filters for tasks as well as for events. The task filter | ||
| 405 | affects both the graph and the list, but the graph and list each have a separate | ||
| 406 | event filter. | ||
| 407 | <p> | ||
| 408 | |||
| 409 | <h2><a name="filter-task">Task Filter</a></h2> | ||
| 410 | |||
| 411 | <p> | ||
| 412 | The task filter is currently set by a right mouse click over | ||
| 413 | an event on either the graph or the list view, and by selecting the option to add or remove the | ||
| 414 | task to/from the task filter. The tasks within the task filter are the same for | ||
| 415 | both the graph and list, but each can be enabled separately. | ||
| 416 | </p> | ||
| 417 | |||
| 418 | <p> | ||
| 419 | There are two types of task filters: | ||
| 420 | </p> | ||
| 421 | |||
| 422 | <ul> | ||
| 423 | <li>Task Filter - only show tasks that are in this filter | ||
| 424 | <li>Hide Tasks - do not display the tasks within this filter | ||
| 425 | </ul> | ||
| 426 | |||
| 427 | <p> | ||
| 428 | If there are any tasks within the Task Filter then only those tasks will be displayed | ||
| 429 | when the filter is enabled. Any task within the Hide Tasks filter will not be | ||
| 430 | displayed, even if that same task is in the Task Filter. | ||
| 431 | </p> | ||
| 432 | |||
| 433 | <img src="images/kshark-filter-task-menu.png"> | ||
| 434 | |||
| 435 | <p> | ||
| 436 | When either filter contains a task, the filter can be enabled. | ||
| 437 | </p> | ||
| 438 | |||
| 439 | <img src="images/kshark-list-enable-filter-1.png"> | ||
| 440 | |||
| 441 | <p> | ||
| 442 | When a task is not in the "Task Filter", the pop up will show the | ||
| 443 | menu item "Add task". When a task is in the "Task Filter" the | ||
| 444 | pop up will show "Remove task". | ||
| 445 | </p> | ||
| 446 | |||
| 447 | <p> | ||
| 448 | When a task is not in the "Hide Tasks", the pop up will show the | ||
| 449 | menu item "Hide task". When a task is in the "Hide Tasks", the | ||
| 450 | pop up will show "Show task". | ||
| 451 | </p> | ||
| 452 | |||
| 453 | <h4>The scheduling events</h4> | ||
| 454 | |||
| 455 | <p> | ||
| 456 | The events "sched_switch", "sched_wakeup", and "sched_wakeup_new" are treated | ||
| 457 | differently by the task filter. Because these events deal with two tasks | ||
| 458 | (previous and next, waker and wakee), if either of the tasks should be visible | ||
| 459 | then that event is visible regardless if the other task should be hidden. | ||
| 460 | This may seem confusing when an event that is hidden shows up in the Task column. | ||
| 461 | </p> | ||
| 462 | |||
| 463 | <h2><a name="filter-event">Event Filter</a></h2> | ||
| 464 | |||
| 465 | <p> | ||
| 466 | The graph and list view each have their own event filter. The event filters | ||
| 467 | are enabled through the Filter menu on the top menu-bar. | ||
| 468 | </p> | ||
| 469 | |||
| 470 | <img src="images/kshark-filter.png"> | ||
| 471 | |||
| 472 | <p> | ||
| 473 | Selecting either the "list events" or "graph events" will bring up the event | ||
| 474 | dialog with the events that are visible selected. | ||
| 475 | </p> | ||
| 476 | |||
| 477 | <p> | ||
| 478 | Note: these do not mean that the events exist in the trace.dat file. They are | ||
| 479 | selected if the events are not to be hidden. Events that do not exist in the trace | ||
| 480 | will not be displayed regardless of whether or not they are filtered. | ||
| 481 | </p> | ||
| 482 | |||
| 483 | <img src="images/kshark-filter-events.png"> | ||
| 484 | |||
| 485 | <p> | ||
| 486 | Clicking on "All" or any of the systems will either deselect all events underneath | ||
| 487 | or select all events underneath depending on the previous state of the box being | ||
| 488 | selected. By deselecting all events, it makes it easier to enable just a few individual events. | ||
| 489 | <p> | ||
| 490 | |||
| 491 | <img src="images/kshark-filter-events-sched.png"> | ||
| 492 | |||
| 493 | <p> | ||
| 494 | If it is desired that the graph and list view have the same events filtered, then just | ||
| 495 | set up the desired filtering in one and then synchronize the other through | ||
| 496 | the filter menu. | ||
| 497 | </p> | ||
| 498 | |||
| 499 | <img src="images/kshark-filter-sync-graph-1.png"> | ||
| 500 | |||
| 501 | <ul> | ||
| 502 | <li><b>sync graph events with list</b> - will set the graph event filter to be the same | ||
| 503 | as what is in the list filter. | ||
| 504 | <li><b>sync list events with graph</b> - will set the list event filter to be the same | ||
| 505 | as what is in the graph filter. | ||
| 506 | </ul> | ||
| 507 | |||
| 508 | <h3><a name="filter-adv-event">Advanced Event Filter</a></h3> | ||
| 509 | |||
| 510 | <p> | ||
| 511 | Filtering on events may not be enough. The ability to filter on the content | ||
| 512 | of individual events may be needed. In order to accomplish this, the advanced event | ||
| 513 | filtering is used. Selecting the "list advanced event" or "graph advanced event" | ||
| 514 | from the Filter menu will pop up the advanced event filtering dialog. | ||
| 515 | The graph and list view each have their own advanced event filter. | ||
| 516 | </p> | ||
| 517 | |||
| 518 | <img src="images/kshark-filter-advance-1.png"> | ||
| 519 | |||
| 520 | <p> | ||
| 521 | The "Filter:" entry at the bottom of the dialog is where the advanced filter is | ||
| 522 | written. Above that is helper buttons to pick events, operations and event fields. | ||
| 523 | The syntax of the filter is: | ||
| 524 | <p> | ||
| 525 | |||
| 526 | <pre> | ||
| 527 | FILTER := EVENTS | EVENTS ':' EXPRESSION | ||
| 528 | EVENTS := EVENTS ',' EVENTS | SYSTEM '/' EVENT | SYSTEM | EVENT | ||
| 529 | SYSTEM := any system name | ||
| 530 | EVENT := any event name | ||
| 531 | EXPRESSION := EXPRESSION BOOL EXPRESSION | '(' EXPRESSION ')' | OPERATION | ||
| 532 | BOOL := '&&' | '||' | ||
| 533 | OPERATION := '!' EXPRESSION | LVALUE CMP RVALUE | LVALUE STRCMP STRVALUE | ||
| 534 | CMP := '>' | '<' | '==' | '>=' | '<=' | '!=' | ||
| 535 | STRCMP := '==' | '!=' | '=~' | '!~' | ||
| 536 | RVALUE := integer | FIELD | ||
| 537 | STRVALUE := string (double quoted value) | FIELD | ||
| 538 | LVALUE := FIELD | EXPR | ||
| 539 | EXPR := FIELD OP RVALUE | '(' EXPR ')' | EXPR OP EXPR | ||
| 540 | FIELD := a field name of an event | ||
| 541 | OP := '+' | '-' | '*' | '/' | '<<' | '>>' | '&' | '!' | ||
| 542 | </pre> | ||
| 543 | |||
| 544 | <p> | ||
| 545 | Spaces are ignored. The example used in the dialog figure: | ||
| 546 | </p> | ||
| 547 | |||
| 548 | <pre> | ||
| 549 | sched/sched_switch : next_prio < 100 && (prev_prio > 100 && prev_pid != 0) | ||
| 550 | </pre> | ||
| 551 | |||
| 552 | <p> | ||
| 553 | The <tt>sched/</tt> is not necessary because without it, the filter will process all events | ||
| 554 | named <tt>sched_switch</tt>, and since there is only one event | ||
| 555 | that has that name, including the <tt>sched/</tt> is redundant. | ||
| 556 | <p> | ||
| 557 | |||
| 558 | <p> | ||
| 559 | The <tt>next_prio</tt>, <tt>prev_prio</tt> and <tt>prev_pid</tt> are all | ||
| 560 | event fields of the <tt>sched_swich</tt> event. | ||
| 561 | </p> | ||
| 562 | |||
| 563 | <p> | ||
| 564 | If just <tt>sched</tt> was used and the <tt>/sched_switch</tt> was omitted, it would | ||
| 565 | still be a valid filter, but it would behave differently. By just specifying | ||
| 566 | a system, the filter will run on all events within that system. When a field | ||
| 567 | is encountered that does not belong to an event, then that compare will be set to false. | ||
| 568 | </p> | ||
| 569 | |||
| 570 | <pre> | ||
| 571 | sched : prev_pid != 0 | ||
| 572 | sched : !(prev_pid == 0) | ||
| 573 | </pre> | ||
| 574 | |||
| 575 | <p> | ||
| 576 | The above two filters are not equivalent. They are for the <tt>sched_switch</tt> event, | ||
| 577 | but not for the other events. The first filter will return false for all events | ||
| 578 | that do not contain the <tt>prev_pid</tt> field, but the second filter would return | ||
| 579 | true for all events that do not contain that field. Again, if the event does | ||
| 580 | not contain a field, just that compare will be evaluated to false, not the entire | ||
| 581 | expression. This means for events that do not have the <tt>prev_pid</tt> field, | ||
| 582 | the above filters would be equivalent to: | ||
| 583 | </p> | ||
| 584 | |||
| 585 | <pre> | ||
| 586 | sched : FALSE | ||
| 587 | sched : !(FALSE) | ||
| 588 | </pre> | ||
| 589 | |||
| 590 | <p> | ||
| 591 | Letting filters contain fields that do not belong to an event be valid | ||
| 592 | allows for various tricks where two events can share the same | ||
| 593 | filter. | ||
| 594 | </p> | ||
| 595 | |||
| 596 | <pre> | ||
| 597 | sched_switch, sched_wake.* : next_pid == 1 || pid == 1 | ||
| 598 | </pre> | ||
| 599 | |||
| 600 | <p> | ||
| 601 | The schedule events that have <tt>next_pid</tt> and not <tt>pid</tt> as a field | ||
| 602 | will just compare the first part of the <tt>||</tt> and those events with | ||
| 603 | <tt>pid</tt> but without <tt>next_pid</tt> will be compared against the second | ||
| 604 | part of the <tt>||</tt> | ||
| 605 | </p> | ||
| 606 | |||
| 607 | <p> | ||
| 608 | Notice that event names in the filter can be regular expressions. | ||
| 609 | </p> | ||
| 610 | |||
| 611 | <p> | ||
| 612 | String fields can have regular expressions used in their comparing if | ||
| 613 | <tt>=~</tt> or <tt>!~</tt> are used. | ||
| 614 | </p> | ||
| 615 | |||
| 616 | <pre> | ||
| 617 | sched_switch : next_comm =~ "^events/[23]$" | ||
| 618 | </pre> | ||
| 619 | |||
| 620 | <p> | ||
| 621 | The available regular expressions are described in <b>regex(7)</b>. | ||
| 622 | </p> | ||
| 623 | |||
| 624 | <p> | ||
| 625 | Note: When adding an advanced filter, all non-advanced filters | ||
| 626 | (added by the event filter dialog box) will be removed, and only the advanced | ||
| 627 | filters will stay. But non-advanced filters may be added after advanced | ||
| 628 | filters have been. The events that have advanced filters will be shaded | ||
| 629 | in the event filter dialog: | ||
| 630 | <p> | ||
| 631 | |||
| 632 | <img src="images/kshark-filter-event-adv-list.png"> | ||
| 633 | |||
| 634 | <p> | ||
| 635 | Just do not click on the advanced filter box and hit "Apply" unless you want to remove | ||
| 636 | the advanced filter. Non-advanced filters can now be selected without affecting | ||
| 637 | the advanced filters. | ||
| 638 | </p> | ||
| 639 | |||
| 640 | <img src="images/kshark-filter-list-adv-irq.png"> | ||
| 641 | |||
| 642 | <p> | ||
| 643 | When advanced filters already exist when the advanced filter dialog box pops up, | ||
| 644 | they will be listed in the area at the top of the dialog. Although | ||
| 645 | one filter may have been written, the list will be per event. A check box | ||
| 646 | is to the left of the filter. When checked, the filter will be deleted if | ||
| 647 | the "Apply" button is selected. | ||
| 648 | </p> | ||
| 649 | |||
| 650 | <img src="images/kshark-filter-del-adv.png"> | ||
| 651 | |||
| 652 | </body> | ||
| 653 | </html> | ||
diff --git a/Documentation/Makefile b/Documentation/Makefile index b7c17e7..be3711f 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile | |||
| @@ -87,7 +87,25 @@ $(MAN1_INSTALL): %.1.install : %.1 force | |||
| 87 | $(MAN5_INSTALL): %.5.install : %.5 force | 87 | $(MAN5_INSTALL): %.5.install : %.5 force |
| 88 | $(Q)$(call do_install,$<,$(man_dir_SQ)/man5) | 88 | $(Q)$(call do_install,$<,$(man_dir_SQ)/man5) |
| 89 | 89 | ||
| 90 | install: $(MAN1_INSTALL) $(MAN5_INSTALL) | 90 | html_dir = $(src)/HTML |
| 91 | image_dir = $(html_dir)/images | ||
| 92 | |||
| 93 | HTML = $(wildcard $(html_dir)/*.html) | ||
| 94 | IMGS = $(wildcard $(image_dir)/*.png) | ||
| 95 | |||
| 96 | HTML_INSTALL = $(subst .html,.html.install,$(HTML)) | ||
| 97 | IMGS_INSTALL = $(subst .png,.png.install,$(IMGS)) | ||
| 98 | |||
| 99 | $(HTML_INSTALL): %.html.install : %.html force | ||
| 100 | $(Q)$(call do_install, $<, '$(html_install_SQ)') | ||
| 101 | |||
| 102 | $(IMGS_INSTALL): %.png.install : %.png force | ||
| 103 | $(Q)$(call do_install, $<, '$(img_install_SQ)') | ||
| 104 | |||
| 105 | |||
| 106 | GUI_INSTALL = $(HTML_INSTALL) $(IMGS_INSTALL) | ||
| 107 | |||
| 108 | install: $(MAN1_INSTALL) $(MAN5_INSTALL) $(GUI_INSTALL) | ||
| 91 | 109 | ||
| 92 | clean: | 110 | clean: |
| 93 | (cd $(obj); \ | 111 | (cd $(obj); \ |
| @@ -30,8 +30,13 @@ bindir_relative = bin | |||
| 30 | bindir = $(prefix)/$(bindir_relative) | 30 | bindir = $(prefix)/$(bindir_relative) |
| 31 | man_dir = $(prefix)/share/man | 31 | man_dir = $(prefix)/share/man |
| 32 | man_dir_SQ = '$(subst ','\'',$(man_dir))' | 32 | man_dir_SQ = '$(subst ','\'',$(man_dir))' |
| 33 | html_install = $(prefix)/share/kernelshark/html | ||
| 34 | html_install_SQ = '$(subst ','\'',$(html_install))' | ||
| 35 | img_install = $(prefix)/share/kernelshark/html/images | ||
| 36 | img_install_SQ = '$(subst ','\'',$(img_install))' | ||
| 33 | 37 | ||
| 34 | export man_dir man_dir_SQ INSTALL | 38 | export man_dir man_dir_SQ html_install html_install_SQ INSTALL |
| 39 | export img_install img_install_SQ | ||
| 35 | export DESTDIR DESTDIR_SQ | 40 | export DESTDIR DESTDIR_SQ |
| 36 | 41 | ||
| 37 | ifeq ($(prefix),$(HOME)) | 42 | ifeq ($(prefix),$(HOME)) |
| @@ -46,6 +51,9 @@ PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))' | |||
| 46 | PYTHON_DIR_SQ = '$(subst ','\'',$(PYTHON_DIR))' | 51 | PYTHON_DIR_SQ = '$(subst ','\'',$(PYTHON_DIR))' |
| 47 | endif | 52 | endif |
| 48 | 53 | ||
| 54 | HELP_DIR = -DHELP_DIR=$(html_install) | ||
| 55 | HELP_DIR_SQ = '$(subst ','\'',$(HELP_DIR))' | ||
| 56 | |||
| 49 | # copy a bit from Linux kbuild | 57 | # copy a bit from Linux kbuild |
| 50 | 58 | ||
| 51 | ifeq ("$(origin V)", "command line") | 59 | ifeq ("$(origin V)", "command line") |
| @@ -120,7 +128,7 @@ python_dir_SQ = $(subst ','\'',$(python_dir)) | |||
| 120 | LIBS = -L. -ltracecmd -ldl | 128 | LIBS = -L. -ltracecmd -ldl |
| 121 | LIB_FILE = libtracecmd.a | 129 | LIB_FILE = libtracecmd.a |
| 122 | 130 | ||
| 123 | PACKAGES= gtk+-2.0 | 131 | PACKAGES= gtk+-2.0 libxml-2.0 |
| 124 | 132 | ||
| 125 | ifndef BUILDGUI | 133 | ifndef BUILDGUI |
| 126 | BUILDGUI = 0 | 134 | BUILDGUI = 0 |
| @@ -148,6 +156,7 @@ REBUILD_GUI = /bin/true | |||
| 148 | G = | 156 | G = |
| 149 | N = @/bin/true || | 157 | N = @/bin/true || |
| 150 | 158 | ||
| 159 | CONFIG_FLAGS += $(HELP_DIR_SQ) | ||
| 151 | else | 160 | else |
| 152 | 161 | ||
| 153 | CONFIG_INCLUDES = | 162 | CONFIG_INCLUDES = |
| @@ -237,16 +246,17 @@ $(obj)/%.o: $(src)/%.c | |||
| 237 | %.o: $(src)/%.c | 246 | %.o: $(src)/%.c |
| 238 | $(Q)$(call check_gui) | 247 | $(Q)$(call check_gui) |
| 239 | 248 | ||
| 249 | TRACE_GUI_OBJS = trace-filter.o trace-compat.o trace-hash.o trace-dialog.o \ | ||
| 250 | trace-xml.o | ||
| 240 | TRACE_CMD_OBJS = trace-cmd.o trace-usage.o trace-read.o trace-split.o trace-listen.o | 251 | TRACE_CMD_OBJS = trace-cmd.o trace-usage.o trace-read.o trace-split.o trace-listen.o |
| 241 | TRACE_VIEW_OBJS = trace-view.o trace-view-store.o trace-filter.o trace-compat.o \ | 252 | TRACE_VIEW_OBJS = trace-view.o trace-view-store.o |
| 242 | trace-hash.o | 253 | TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o trace-plot-cpu.o trace-plot-task.o |
| 243 | TRACE_GRAPH_OBJS = trace-graph.o trace-compat.o trace-hash.o trace-filter.o \ | 254 | TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS) $(TRACE_GUI_OBJS) |
| 244 | trace-plot.o trace-plot-cpu.o trace-plot-task.o | 255 | TRACE_GRAPH_MAIN_OBJS = trace-graph-main.o $(TRACE_GRAPH_OBJS) $(TRACE_GUI_OBJS) |
| 245 | TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS) | 256 | KERNEL_SHARK_OBJS = $(TRACE_VIEW_OBJS) $(TRACE_GRAPH_OBJS) $(TRACE_GUI_OBJS) \ |
| 246 | TRACE_GRAPH_MAIN_OBJS = trace-graph-main.o $(TRACE_GRAPH_OBJS) | 257 | kernel-shark.o |
| 247 | KERNEL_SHARK_OBJS = $(TRACE_VIEW_OBJS) $(TRACE_GRAPH_OBJS) kernel-shark.o | 258 | |
| 248 | 259 | PEVENT_LIB_OBJS = parse-events.o trace-seq.o parse-filter.o parse-utils.o | |
| 249 | PEVENT_LIB_OBJS = parse-events.o trace-seq.o parse-filter.o | ||
| 250 | TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \ | 260 | TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \ |
| 251 | trace-output.o trace-record.o | 261 | trace-output.o trace-record.o |
| 252 | 262 | ||
diff --git a/kernel-shark.c b/kernel-shark.c index fcb0f54..9ca3942 100644 --- a/kernel-shark.c +++ b/kernel-shark.c | |||
| @@ -27,13 +27,18 @@ | |||
| 27 | #include <sys/stat.h> | 27 | #include <sys/stat.h> |
| 28 | #include <unistd.h> | 28 | #include <unistd.h> |
| 29 | #include <gtk/gtk.h> | 29 | #include <gtk/gtk.h> |
| 30 | #include <errno.h> | ||
| 30 | #include <getopt.h> | 31 | #include <getopt.h> |
| 31 | 32 | ||
| 32 | #include "trace-compat.h" | 33 | #include "trace-compat.h" |
| 33 | #include "trace-cmd.h" | 34 | #include "trace-cmd.h" |
| 35 | #include "trace-gui.h" | ||
| 34 | #include "kernel-shark.h" | 36 | #include "kernel-shark.h" |
| 35 | #include "version.h" | 37 | #include "version.h" |
| 36 | 38 | ||
| 39 | #define ___stringify(X) #X | ||
| 40 | #define __stringify(X) ___stringify(X) | ||
| 41 | |||
| 37 | #define DEBUG_LEVEL 0 | 42 | #define DEBUG_LEVEL 0 |
| 38 | #if DEBUG_LEVEL > 0 | 43 | #if DEBUG_LEVEL > 0 |
| 39 | # define dprintf(l, x...) \ | 44 | # define dprintf(l, x...) \ |
| @@ -59,6 +64,85 @@ void usage(char *prog) | |||
| 59 | printf(" -i input_file, default is %s\n", default_input_file); | 64 | printf(" -i input_file, default is %s\n", default_input_file); |
| 60 | } | 65 | } |
| 61 | 66 | ||
| 67 | /* | ||
| 68 | * trace_sync_select_menu - helper function to the syncing of list and graph filters | ||
| 69 | * | ||
| 70 | * Creates a pop up dialog with the selections given. The selections will be | ||
| 71 | * radio buttons to the user. The keep is a value that will be set to the check | ||
| 72 | * box (default on) if the user wants to keep the selection persistant. | ||
| 73 | */ | ||
| 74 | static int trace_sync_select_menu(const gchar *title, | ||
| 75 | gchar **selections, gboolean *keep) | ||
| 76 | { | ||
| 77 | GtkWidget *dialog; | ||
| 78 | GtkWidget *radio; | ||
| 79 | GtkWidget *check; | ||
| 80 | GSList *group; | ||
| 81 | int result; | ||
| 82 | int i; | ||
| 83 | |||
| 84 | dialog = gtk_dialog_new_with_buttons(title, | ||
| 85 | NULL, | ||
| 86 | GTK_DIALOG_MODAL, | ||
| 87 | "OK", GTK_RESPONSE_ACCEPT, | ||
| 88 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | ||
| 89 | NULL); | ||
| 90 | |||
| 91 | radio = gtk_radio_button_new_with_label(NULL, selections[0]); | ||
| 92 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), radio, TRUE, TRUE, 0); | ||
| 93 | gtk_widget_show(radio); | ||
| 94 | |||
| 95 | group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio)); | ||
| 96 | |||
| 97 | for (i = 1; selections[i]; i++) { | ||
| 98 | radio = gtk_radio_button_new_with_label(group, selections[i]); | ||
| 99 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), radio, TRUE, TRUE, 0); | ||
| 100 | gtk_widget_show(radio); | ||
| 101 | } | ||
| 102 | |||
| 103 | check = gtk_check_button_new_with_label("Keep the filters in sync?"); | ||
| 104 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), check, TRUE, TRUE, 0); | ||
| 105 | gtk_widget_show(check); | ||
| 106 | |||
| 107 | gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE); | ||
| 108 | |||
| 109 | result = gtk_dialog_run(GTK_DIALOG(dialog)); | ||
| 110 | switch (result) { | ||
| 111 | case GTK_RESPONSE_ACCEPT: | ||
| 112 | i = 0; | ||
| 113 | for (i = 0; group; i++, group = g_slist_next(group)) { | ||
| 114 | radio = group->data; | ||
| 115 | if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radio))) | ||
| 116 | break; | ||
| 117 | } | ||
| 118 | result = i; | ||
| 119 | *keep = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check)); | ||
| 120 | break; | ||
| 121 | default: | ||
| 122 | result = -1; | ||
| 123 | } | ||
| 124 | |||
| 125 | gtk_widget_destroy(dialog); | ||
| 126 | return result; | ||
| 127 | } | ||
| 128 | |||
| 129 | static void update_tree_view_filters(struct shark_info *info, | ||
| 130 | struct filter_task *task_filter, | ||
| 131 | struct filter_task *hide_tasks) | ||
| 132 | { | ||
| 133 | if (info->list_filter_enabled) | ||
| 134 | trace_view_update_filters(info->treeview, | ||
| 135 | task_filter, hide_tasks); | ||
| 136 | |||
| 137 | if (filter_task_count(task_filter) || | ||
| 138 | filter_task_count(hide_tasks)) | ||
| 139 | info->list_filter_available = 1; | ||
| 140 | else { | ||
| 141 | info->list_filter_enabled = 0; | ||
| 142 | info->list_filter_available = 0; | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 62 | /* graph callbacks */ | 146 | /* graph callbacks */ |
| 63 | 147 | ||
| 64 | /* convert_nano() and print_time() are copied from trace-graph.c for debugging | 148 | /* convert_nano() and print_time() are copied from trace-graph.c for debugging |
| @@ -108,15 +192,20 @@ static void ks_graph_filter(struct graph_info *ginfo, | |||
| 108 | cbs = trace_graph_get_callbacks(ginfo); | 192 | cbs = trace_graph_get_callbacks(ginfo); |
| 109 | info = container_of(cbs, struct shark_info, graph_cbs); | 193 | info = container_of(cbs, struct shark_info, graph_cbs); |
| 110 | 194 | ||
| 111 | if (info->list_filter_enabled) | 195 | if (!info->sync_task_filters) |
| 112 | trace_view_update_filters(info->treeview, | 196 | return; |
| 113 | task_filter, hide_tasks); | 197 | |
| 198 | update_tree_view_filters(info, task_filter, hide_tasks); | ||
| 114 | } | 199 | } |
| 115 | 200 | ||
| 116 | static void free_info(struct shark_info *info) | 201 | static void free_info(struct shark_info *info) |
| 117 | { | 202 | { |
| 118 | tracecmd_close(info->handle); | 203 | tracecmd_close(info->handle); |
| 119 | trace_graph_free_info(info->ginfo); | 204 | trace_graph_free_info(info->ginfo); |
| 205 | |||
| 206 | filter_task_hash_free(info->list_task_filter); | ||
| 207 | filter_task_hash_free(info->list_hide_tasks); | ||
| 208 | |||
| 120 | free(info->ginfo); | 209 | free(info->ginfo); |
| 121 | free(info); | 210 | free(info); |
| 122 | } | 211 | } |
| @@ -134,34 +223,219 @@ static void update_title(GtkWidget *window, const gchar *file) | |||
| 134 | g_free(str); | 223 | g_free(str); |
| 135 | } | 224 | } |
| 136 | 225 | ||
| 226 | static void unsync_task_filters(struct shark_info *info) | ||
| 227 | { | ||
| 228 | info->sync_task_filters = 0; | ||
| 229 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->task_sync_menu), | ||
| 230 | "Sync Graph and List Task Filters"); | ||
| 231 | |||
| 232 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->graph_task_menu), | ||
| 233 | "graph tasks"); | ||
| 234 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->graph_hide_task_menu), | ||
| 235 | "graph hide tasks"); | ||
| 236 | gtk_widget_show(info->list_task_menu); | ||
| 237 | gtk_widget_show(info->list_hide_task_menu); | ||
| 238 | |||
| 239 | /* The list now uses its own hash */ | ||
| 240 | info->list_task_filter = filter_task_hash_copy(info->ginfo->task_filter); | ||
| 241 | info->list_hide_tasks = filter_task_hash_copy(info->ginfo->hide_tasks); | ||
| 242 | } | ||
| 243 | |||
| 244 | static void sync_task_filters(struct shark_info *info) | ||
| 245 | { | ||
| 246 | info->sync_task_filters = 1; | ||
| 247 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->task_sync_menu), | ||
| 248 | "Unsync Graph and List Task Filters"); | ||
| 249 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->graph_task_menu), | ||
| 250 | "tasks"); | ||
| 251 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->graph_hide_task_menu), | ||
| 252 | "hide tasks"); | ||
| 253 | gtk_widget_hide(info->list_task_menu); | ||
| 254 | gtk_widget_hide(info->list_hide_task_menu); | ||
| 255 | } | ||
| 256 | |||
| 257 | static void unsync_event_filters(struct shark_info *info) | ||
| 258 | { | ||
| 259 | info->sync_event_filters = 0; | ||
| 260 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->events_sync_menu), | ||
| 261 | "Sync Graph and List Event Filters"); | ||
| 262 | |||
| 263 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->graph_events_menu), | ||
| 264 | "graph events"); | ||
| 265 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->graph_adv_events_menu), | ||
| 266 | "graph advanced events"); | ||
| 267 | gtk_widget_show(info->list_events_menu); | ||
| 268 | gtk_widget_show(info->list_adv_events_menu); | ||
| 269 | } | ||
| 270 | |||
| 271 | static void sync_event_filters(struct shark_info *info) | ||
| 272 | { | ||
| 273 | info->sync_event_filters = 1; | ||
| 274 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->events_sync_menu), | ||
| 275 | "Unsync Graph and List Event Filters"); | ||
| 276 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->graph_events_menu), | ||
| 277 | "events"); | ||
| 278 | gtk_menu_item_set_label(GTK_MENU_ITEM(info->graph_adv_events_menu), | ||
| 279 | "advanced events"); | ||
| 280 | gtk_widget_hide(info->list_events_menu); | ||
| 281 | gtk_widget_hide(info->list_adv_events_menu); | ||
| 282 | } | ||
| 283 | |||
| 137 | static void | 284 | static void |
| 138 | /* Callback for the clicked signal of the Load button */ | 285 | /* Callback for the clicked signal of the Load button */ |
| 139 | load_clicked (gpointer data) | 286 | load_clicked (gpointer data) |
| 140 | { | 287 | { |
| 141 | struct shark_info *info = data; | 288 | struct shark_info *info = data; |
| 142 | struct tracecmd_input *handle; | 289 | struct tracecmd_input *handle; |
| 143 | GtkWidget *dialog; | ||
| 144 | gchar *filename; | 290 | gchar *filename; |
| 145 | 291 | ||
| 146 | dialog = gtk_file_chooser_dialog_new("Load File", | 292 | filename = trace_get_file_dialog("Load File"); |
| 147 | NULL, | 293 | if (!filename) |
| 148 | GTK_FILE_CHOOSER_ACTION_OPEN, | 294 | return; |
| 149 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | 295 | |
| 150 | GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, | 296 | handle = tracecmd_open(filename); |
| 151 | NULL); | 297 | if (handle) { |
| 152 | if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { | 298 | tracecmd_close(info->handle); |
| 153 | filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); | 299 | info->handle = handle; |
| 154 | handle = tracecmd_open(filename); | 300 | trace_graph_load_handle(info->ginfo, handle); |
| 155 | if (handle) { | 301 | trace_view_reload(info->treeview, handle, info->spin); |
| 156 | tracecmd_close(info->handle); | 302 | update_title(info->window, filename); |
| 157 | info->handle = handle; | ||
| 158 | trace_graph_load_handle(info->ginfo, handle); | ||
| 159 | trace_view_reload(info->treeview, handle, info->spin); | ||
| 160 | update_title(info->window, filename); | ||
| 161 | } | ||
| 162 | g_free(filename); | ||
| 163 | } | 303 | } |
| 164 | gtk_widget_destroy(dialog); | 304 | g_free(filename); |
| 305 | } | ||
| 306 | |||
| 307 | /* Callback for the clicked signal of the Load Filters button */ | ||
| 308 | static void | ||
| 309 | load_filters_clicked (gpointer data) | ||
| 310 | { | ||
| 311 | struct shark_info *info = data; | ||
| 312 | struct graph_info *ginfo = info->ginfo; | ||
| 313 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | ||
| 314 | GtkTreeModel *model; | ||
| 315 | TraceViewStore *store; | ||
| 316 | struct tracecmd_xml_handle *handle; | ||
| 317 | struct filter_task *task_filter; | ||
| 318 | struct filter_task *hide_tasks; | ||
| 319 | struct event_filter *event_filter; | ||
| 320 | gchar *filename; | ||
| 321 | int ret; | ||
| 322 | |||
| 323 | filename = trace_get_file_dialog("Load Filters"); | ||
| 324 | if (!filename) | ||
| 325 | return; | ||
| 326 | |||
| 327 | handle = tracecmd_xml_open(filename); | ||
| 328 | if (!handle) { | ||
| 329 | warning("Could not open %s", filename); | ||
| 330 | goto out; | ||
| 331 | } | ||
| 332 | |||
| 333 | /* Unsync the list and graph filters */ | ||
| 334 | if (info->sync_task_filters) | ||
| 335 | unsync_task_filters(info); | ||
| 336 | if (info->sync_event_filters) | ||
| 337 | unsync_event_filters(info); | ||
| 338 | |||
| 339 | ret = tracecmd_xml_system_exists(handle, | ||
| 340 | "GraphTaskFilter"); | ||
| 341 | if (ret) { | ||
| 342 | filter_task_clear(ginfo->task_filter); | ||
| 343 | filter_task_clear(ginfo->hide_tasks); | ||
| 344 | |||
| 345 | trace_filter_load_filters(handle, | ||
| 346 | "GraphTaskFilter", | ||
| 347 | ginfo->task_filter, | ||
| 348 | ginfo->hide_tasks); | ||
| 349 | trace_graph_refresh_filters(ginfo); | ||
| 350 | } | ||
| 351 | |||
| 352 | ret = tracecmd_xml_system_exists(handle, | ||
| 353 | "ListTaskFilter"); | ||
| 354 | if (ret) { | ||
| 355 | task_filter = info->list_task_filter; | ||
| 356 | hide_tasks = info->list_hide_tasks; | ||
| 357 | filter_task_clear(task_filter); | ||
| 358 | filter_task_clear(hide_tasks); | ||
| 359 | |||
| 360 | trace_filter_load_filters(handle, | ||
| 361 | "ListTaskFilter", | ||
| 362 | task_filter, | ||
| 363 | hide_tasks); | ||
| 364 | update_tree_view_filters(info, task_filter, hide_tasks); | ||
| 365 | } | ||
| 366 | |||
| 367 | trace_graph_load_filters(ginfo, handle); | ||
| 368 | ret = trace_view_load_filters(handle, trace_tree); | ||
| 369 | |||
| 370 | tracecmd_xml_close(handle); | ||
| 371 | |||
| 372 | /* | ||
| 373 | * If the events or tasks filters are the same for both | ||
| 374 | * the list and graph, then sync them back. | ||
| 375 | */ | ||
| 376 | if (filter_task_compare(ginfo->task_filter, | ||
| 377 | info->list_task_filter) && | ||
| 378 | filter_task_compare(ginfo->hide_tasks, | ||
| 379 | info->list_hide_tasks)) | ||
| 380 | sync_task_filters(info); | ||
| 381 | |||
| 382 | model = gtk_tree_view_get_model(trace_tree); | ||
| 383 | if (!model) | ||
| 384 | goto out; | ||
| 385 | |||
| 386 | store = TRACE_VIEW_STORE(model); | ||
| 387 | event_filter = trace_view_store_get_event_filter(store); | ||
| 388 | |||
| 389 | if (pevent_filter_compare(event_filter, ginfo->event_filter)) | ||
| 390 | sync_event_filters(info); | ||
| 391 | |||
| 392 | out: | ||
| 393 | g_free(filename); | ||
| 394 | |||
| 395 | } | ||
| 396 | |||
| 397 | /* Callback for the clicked signal of the Save Filters button */ | ||
| 398 | static void | ||
| 399 | save_filters_clicked (gpointer data) | ||
| 400 | { | ||
| 401 | struct shark_info *info = data; | ||
| 402 | struct graph_info *ginfo = info->ginfo; | ||
| 403 | struct tracecmd_xml_handle *handle; | ||
| 404 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | ||
| 405 | struct filter_task *task_filter; | ||
| 406 | struct filter_task *hide_tasks; | ||
| 407 | gchar *filename; | ||
| 408 | |||
| 409 | filename = trace_get_file_dialog("Save Filters"); | ||
| 410 | if (!filename) | ||
| 411 | return; | ||
| 412 | |||
| 413 | handle = tracecmd_xml_create(filename, VERSION_STRING); | ||
| 414 | if (!handle) | ||
| 415 | warning("Could not create %s", filename); | ||
| 416 | g_free(filename); | ||
| 417 | |||
| 418 | trace_view_save_filters(handle, trace_tree); | ||
| 419 | trace_graph_save_filters(ginfo, handle); | ||
| 420 | |||
| 421 | trace_filter_save_filters(handle, | ||
| 422 | "GraphTaskFilter", | ||
| 423 | ginfo->task_filter, | ||
| 424 | ginfo->hide_tasks); | ||
| 425 | |||
| 426 | if (info->sync_task_filters) { | ||
| 427 | task_filter = ginfo->task_filter; | ||
| 428 | hide_tasks = ginfo->hide_tasks; | ||
| 429 | } else { | ||
| 430 | task_filter = info->list_task_filter; | ||
| 431 | hide_tasks = info->list_hide_tasks; | ||
| 432 | } | ||
| 433 | |||
| 434 | trace_filter_save_filters(handle, | ||
| 435 | "ListTaskFilter", | ||
| 436 | task_filter, hide_tasks); | ||
| 437 | |||
| 438 | tracecmd_xml_close(handle); | ||
| 165 | } | 439 | } |
| 166 | 440 | ||
| 167 | /* Callback for the clicked signal of the Exit button */ | 441 | /* Callback for the clicked signal of the Exit button */ |
| @@ -187,16 +461,28 @@ delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) | |||
| 187 | return TRUE; | 461 | return TRUE; |
| 188 | } | 462 | } |
| 189 | 463 | ||
| 190 | /* Callback for the clicked signal of the Events filter button */ | 464 | /* Callback for the clicked signal of the tasks sync filter button */ |
| 191 | static void | 465 | static void |
| 192 | list_events_clicked (gpointer data) | 466 | sync_task_filter_clicked (GtkWidget *subitem, gpointer data) |
| 193 | { | 467 | { |
| 194 | struct shark_info *info = data; | 468 | struct shark_info *info = data; |
| 195 | struct event_filter *event_filter; | 469 | struct filter_task *task_filter; |
| 470 | struct filter_task *hide_tasks; | ||
| 196 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | 471 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); |
| 197 | GtkTreeModel *model; | 472 | GtkTreeModel *model; |
| 198 | TraceViewStore *store; | 473 | TraceViewStore *store; |
| 199 | gboolean all_events; | 474 | gboolean keep; |
| 475 | gchar *selections[] = { "Sync List Filter with Graph Filter", | ||
| 476 | "Sync Graph Filter with List Filter", | ||
| 477 | NULL }; | ||
| 478 | int result; | ||
| 479 | |||
| 480 | if (info->sync_task_filters) { | ||
| 481 | /* Separate the List and Graph filters */ | ||
| 482 | |||
| 483 | unsync_task_filters(info); | ||
| 484 | return; | ||
| 485 | } | ||
| 200 | 486 | ||
| 201 | model = gtk_tree_view_get_model(trace_tree); | 487 | model = gtk_tree_view_get_model(trace_tree); |
| 202 | if (!model) | 488 | if (!model) |
| @@ -204,40 +490,204 @@ list_events_clicked (gpointer data) | |||
| 204 | 490 | ||
| 205 | store = TRACE_VIEW_STORE(model); | 491 | store = TRACE_VIEW_STORE(model); |
| 206 | 492 | ||
| 207 | all_events = trace_view_store_get_all_events_enabled(store); | 493 | /* If they are already equal, then just perminently sync them */ |
| 208 | event_filter = trace_view_store_get_event_filter(store); | 494 | if (filter_task_compare(info->ginfo->task_filter, |
| 495 | info->list_task_filter) && | ||
| 496 | filter_task_compare(info->ginfo->hide_tasks, | ||
| 497 | info->list_hide_tasks)) | ||
| 498 | result = 2; | ||
| 209 | 499 | ||
| 210 | trace_filter_event_filter_dialog(store->handle, event_filter, | 500 | else |
| 211 | all_events, | 501 | /* Ask user which way to sync */ |
| 212 | trace_view_event_filter_callback, | 502 | result = trace_sync_select_menu("Sync Task Filters", |
| 213 | info->treeview); | 503 | selections, &keep); |
| 504 | |||
| 505 | switch (result) { | ||
| 506 | case 0: | ||
| 507 | /* Sync List Filter with Graph Filter */ | ||
| 508 | filter_task_hash_free(info->list_task_filter); | ||
| 509 | filter_task_hash_free(info->list_hide_tasks); | ||
| 510 | |||
| 511 | info->list_task_filter = NULL; | ||
| 512 | info->list_hide_tasks = NULL; | ||
| 513 | |||
| 514 | task_filter = info->ginfo->task_filter; | ||
| 515 | hide_tasks = info->ginfo->hide_tasks; | ||
| 516 | |||
| 517 | if (!keep) { | ||
| 518 | info->list_task_filter = filter_task_hash_copy(task_filter); | ||
| 519 | info->list_hide_tasks = filter_task_hash_copy(hide_tasks); | ||
| 520 | } | ||
| 521 | |||
| 522 | update_tree_view_filters(info, task_filter, hide_tasks); | ||
| 523 | |||
| 524 | break; | ||
| 525 | case 1: | ||
| 526 | /* Sync Graph Filter with List Filter */ | ||
| 527 | trace_graph_update_filters(info->ginfo, | ||
| 528 | info->list_task_filter, | ||
| 529 | info->list_hide_tasks); | ||
| 530 | |||
| 531 | if (keep) { | ||
| 532 | filter_task_hash_free(info->list_task_filter); | ||
| 533 | filter_task_hash_free(info->list_hide_tasks); | ||
| 534 | |||
| 535 | info->list_task_filter = NULL; | ||
| 536 | info->list_hide_tasks = NULL; | ||
| 537 | } | ||
| 538 | break; | ||
| 539 | case 2: | ||
| 540 | keep = 1; | ||
| 541 | break; | ||
| 542 | default: | ||
| 543 | keep = 0; | ||
| 544 | } | ||
| 545 | |||
| 546 | if (keep) | ||
| 547 | sync_task_filters(info); | ||
| 214 | } | 548 | } |
| 215 | 549 | ||
| 550 | /* Callback for the clicked signal of the events sync filter button */ | ||
| 216 | static void | 551 | static void |
| 217 | graph_events_clicked (gpointer data) | 552 | sync_events_filter_clicked (GtkWidget *subitem, gpointer data) |
| 218 | { | 553 | { |
| 219 | struct shark_info *info = data; | 554 | struct shark_info *info = data; |
| 220 | struct graph_info *ginfo = info->ginfo; | 555 | struct graph_info *ginfo = info->ginfo; |
| 556 | struct event_filter *event_filter; | ||
| 557 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | ||
| 558 | GtkTreeModel *model; | ||
| 559 | TraceViewStore *store; | ||
| 560 | gboolean keep; | ||
| 221 | gboolean all_events; | 561 | gboolean all_events; |
| 562 | gchar *selections[] = { "Sync List Filter with Graph Filter", | ||
| 563 | "Sync Graph Filter with List Filter", | ||
| 564 | NULL }; | ||
| 565 | int result; | ||
| 566 | |||
| 567 | if (info->sync_event_filters) { | ||
| 568 | /* Separate the List and Graph filters */ | ||
| 569 | unsync_event_filters(info); | ||
| 570 | return; | ||
| 571 | } | ||
| 222 | 572 | ||
| 223 | all_events = ginfo->all_events; | 573 | model = gtk_tree_view_get_model(trace_tree); |
| 574 | if (!model) | ||
| 575 | return; | ||
| 224 | 576 | ||
| 225 | trace_filter_event_filter_dialog(info->handle, | 577 | store = TRACE_VIEW_STORE(model); |
| 226 | ginfo->event_filter, | 578 | event_filter = trace_view_store_get_event_filter(store); |
| 227 | all_events, | 579 | |
| 228 | trace_graph_event_filter_callback, | 580 | /* If they are already equal, then just perminently sync them */ |
| 229 | ginfo); | 581 | if (pevent_filter_compare(event_filter, ginfo->event_filter)) |
| 582 | result = 2; | ||
| 583 | else | ||
| 584 | /* Ask user which way to sync */ | ||
| 585 | result = trace_sync_select_menu("Sync Event Filters", | ||
| 586 | selections, &keep); | ||
| 587 | |||
| 588 | switch (result) { | ||
| 589 | case 0: | ||
| 590 | /* Sync List Filter with Graph Filter */ | ||
| 591 | all_events = ginfo->all_events; | ||
| 592 | |||
| 593 | trace_view_copy_filter(info->treeview, all_events, | ||
| 594 | ginfo->event_filter); | ||
| 595 | break; | ||
| 596 | case 1: | ||
| 597 | /* Sync Graph Filter with List Filter */ | ||
| 598 | all_events = trace_view_store_get_all_events_enabled(store); | ||
| 599 | |||
| 600 | trace_graph_copy_filter(info->ginfo, all_events, | ||
| 601 | event_filter); | ||
| 602 | break; | ||
| 603 | case 2: | ||
| 604 | keep = 1; | ||
| 605 | break; | ||
| 606 | default: | ||
| 607 | keep = 0; | ||
| 608 | } | ||
| 609 | |||
| 610 | if (keep) | ||
| 611 | sync_event_filters(info); | ||
| 230 | } | 612 | } |
| 231 | 613 | ||
| 232 | /* Callback for the clicked signal of the List advanced filter button */ | 614 | static void filter_list_enable_clicked (gpointer data); |
| 615 | |||
| 233 | static void | 616 | static void |
| 234 | adv_list_filter_clicked (gpointer data) | 617 | __update_list_task_filter_callback(struct shark_info *info, |
| 618 | gboolean accept, | ||
| 619 | gint *selected, | ||
| 620 | struct filter_task *task_filter) | ||
| 621 | { | ||
| 622 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | ||
| 623 | GtkTreeModel *model; | ||
| 624 | TraceViewStore *store; | ||
| 625 | int i; | ||
| 626 | |||
| 627 | if (!accept) | ||
| 628 | return; | ||
| 629 | |||
| 630 | model = gtk_tree_view_get_model(trace_tree); | ||
| 631 | if (!model) | ||
| 632 | return; | ||
| 633 | |||
| 634 | store = TRACE_VIEW_STORE(model); | ||
| 635 | |||
| 636 | filter_task_clear(task_filter); | ||
| 637 | |||
| 638 | if (selected) { | ||
| 639 | for (i = 0; selected[i] >= 0; i++) | ||
| 640 | filter_task_add_pid(task_filter, selected[i]); | ||
| 641 | } | ||
| 642 | |||
| 643 | update_tree_view_filters(info, info->list_task_filter, info->list_hide_tasks); | ||
| 644 | |||
| 645 | /* | ||
| 646 | * The menu filters always enable the filters. | ||
| 647 | */ | ||
| 648 | if (info->list_filter_available && !info->list_filter_enabled) | ||
| 649 | filter_list_enable_clicked(info); | ||
| 650 | } | ||
| 651 | |||
| 652 | static void | ||
| 653 | update_list_task_filter_callback(gboolean accept, | ||
| 654 | gint *selected, | ||
| 655 | gint *non_select, | ||
| 656 | gpointer data) | ||
| 235 | { | 657 | { |
| 236 | struct shark_info *info = data; | 658 | struct shark_info *info = data; |
| 237 | struct event_filter *event_filter; | 659 | |
| 660 | __update_list_task_filter_callback(info, accept, selected, | ||
| 661 | info->list_task_filter); | ||
| 662 | } | ||
| 663 | |||
| 664 | static void | ||
| 665 | update_list_hide_task_filter_callback(gboolean accept, | ||
| 666 | gint *selected, | ||
| 667 | gint *non_select, | ||
| 668 | gpointer data) | ||
| 669 | { | ||
| 670 | struct shark_info *info = data; | ||
| 671 | |||
| 672 | __update_list_task_filter_callback(info, accept, selected, | ||
| 673 | info->list_hide_tasks); | ||
| 674 | } | ||
| 675 | |||
| 676 | /* Callback for the clicked signal of the List Tasks filter button */ | ||
| 677 | static void | ||
| 678 | __list_tasks_clicked (struct shark_info *info, | ||
| 679 | struct filter_task *task_filter, | ||
| 680 | trace_task_cb_func func) | ||
| 681 | { | ||
| 238 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | 682 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); |
| 683 | struct graph_info *ginfo = info->ginfo; | ||
| 239 | GtkTreeModel *model; | 684 | GtkTreeModel *model; |
| 240 | TraceViewStore *store; | 685 | TraceViewStore *store; |
| 686 | gint *selected; | ||
| 687 | gint *tasks; | ||
| 688 | |||
| 689 | if (!ginfo->handle) | ||
| 690 | return; | ||
| 241 | 691 | ||
| 242 | model = gtk_tree_view_get_model(trace_tree); | 692 | model = gtk_tree_view_get_model(trace_tree); |
| 243 | if (!model) | 693 | if (!model) |
| @@ -245,25 +695,137 @@ adv_list_filter_clicked (gpointer data) | |||
| 245 | 695 | ||
| 246 | store = TRACE_VIEW_STORE(model); | 696 | store = TRACE_VIEW_STORE(model); |
| 247 | 697 | ||
| 248 | event_filter = trace_view_store_get_event_filter(store); | 698 | tasks = trace_graph_task_list(ginfo); |
| 699 | selected = filter_task_pids(task_filter); | ||
| 249 | 700 | ||
| 250 | trace_adv_filter_dialog(store->handle, event_filter, | 701 | trace_task_dialog(info->handle, tasks, selected, func, info); |
| 251 | trace_view_adv_filter_callback, trace_tree); | 702 | |
| 703 | free(tasks); | ||
| 704 | free(selected); | ||
| 252 | } | 705 | } |
| 253 | 706 | ||
| 254 | /* Callback for the clicked signal of the Graph advanced filter button */ | ||
| 255 | static void | 707 | static void |
| 256 | adv_graph_filter_clicked (gpointer data) | 708 | list_tasks_clicked (gpointer data) |
| 257 | { | 709 | { |
| 258 | struct shark_info *info = data; | 710 | struct shark_info *info = data; |
| 711 | |||
| 712 | __list_tasks_clicked(info, info->list_task_filter, | ||
| 713 | update_list_task_filter_callback); | ||
| 714 | } | ||
| 715 | |||
| 716 | static void | ||
| 717 | list_hide_tasks_clicked (gpointer data) | ||
| 718 | { | ||
| 719 | struct shark_info *info = data; | ||
| 720 | |||
| 721 | __list_tasks_clicked(info, info->list_hide_tasks, | ||
| 722 | update_list_hide_task_filter_callback); | ||
| 723 | } | ||
| 724 | |||
| 725 | static void | ||
| 726 | __update_graph_task_filter_callback(struct shark_info *info, | ||
| 727 | gboolean accept, | ||
| 728 | gint *selected, | ||
| 729 | struct filter_task *task_filter) | ||
| 730 | { | ||
| 259 | struct graph_info *ginfo = info->ginfo; | 731 | struct graph_info *ginfo = info->ginfo; |
| 732 | int i; | ||
| 260 | 733 | ||
| 261 | trace_adv_filter_dialog(ginfo->handle, ginfo->event_filter, | 734 | if (!accept) |
| 262 | trace_graph_adv_filter_callback, ginfo); | 735 | return; |
| 736 | |||
| 737 | filter_task_clear(task_filter); | ||
| 738 | |||
| 739 | if (selected) { | ||
| 740 | for (i = 0; selected[i] >= 0; i++) | ||
| 741 | filter_task_add_pid(task_filter, selected[i]); | ||
| 742 | } | ||
| 743 | |||
| 744 | trace_graph_refresh_filters(ginfo); | ||
| 745 | |||
| 746 | /* | ||
| 747 | * The menu filters always enable the filters. | ||
| 748 | */ | ||
| 749 | if (ginfo->filter_available) { | ||
| 750 | if (!ginfo->filter_enabled) | ||
| 751 | trace_graph_filter_toggle(info->ginfo); | ||
| 752 | |||
| 753 | if (info->sync_task_filters && !info->list_filter_enabled) | ||
| 754 | filter_list_enable_clicked(info); | ||
| 755 | } | ||
| 263 | } | 756 | } |
| 264 | 757 | ||
| 265 | static void | 758 | static void |
| 266 | sync_graph_events_to_list_clicked (gpointer data) | 759 | update_graph_task_filter_callback(gboolean accept, |
| 760 | gint *selected, | ||
| 761 | gint *non_select, | ||
| 762 | gpointer data) | ||
| 763 | { | ||
| 764 | struct shark_info *info = data; | ||
| 765 | struct graph_info *ginfo = info->ginfo; | ||
| 766 | |||
| 767 | __update_graph_task_filter_callback(info, accept, selected, | ||
| 768 | ginfo->task_filter); | ||
| 769 | } | ||
| 770 | |||
| 771 | static void | ||
| 772 | update_graph_hide_task_filter_callback(gboolean accept, | ||
| 773 | gint *selected, | ||
| 774 | gint *non_select, | ||
| 775 | gpointer data) | ||
| 776 | { | ||
| 777 | struct shark_info *info = data; | ||
| 778 | struct graph_info *ginfo = info->ginfo; | ||
| 779 | |||
| 780 | __update_graph_task_filter_callback(info, accept, selected, | ||
| 781 | ginfo->hide_tasks); | ||
| 782 | } | ||
| 783 | |||
| 784 | /* Callback for the clicked signal of the Tasks filter button */ | ||
| 785 | static void | ||
| 786 | __graph_tasks_clicked (struct shark_info *info, | ||
| 787 | struct filter_task *task_filter, | ||
| 788 | trace_task_cb_func func) | ||
| 789 | { | ||
| 790 | struct graph_info *ginfo = info->ginfo; | ||
| 791 | gint *selected; | ||
| 792 | gint *tasks; | ||
| 793 | |||
| 794 | if (!ginfo->handle) | ||
| 795 | return; | ||
| 796 | |||
| 797 | tasks = trace_graph_task_list(ginfo); | ||
| 798 | selected = filter_task_pids(task_filter); | ||
| 799 | |||
| 800 | trace_task_dialog(ginfo->handle, tasks, selected, func, info); | ||
| 801 | |||
| 802 | free(tasks); | ||
| 803 | free(selected); | ||
| 804 | } | ||
| 805 | |||
| 806 | static void | ||
| 807 | graph_tasks_clicked (gpointer data) | ||
| 808 | { | ||
| 809 | struct shark_info *info = data; | ||
| 810 | struct graph_info *ginfo = info->ginfo; | ||
| 811 | |||
| 812 | __graph_tasks_clicked(info, ginfo->task_filter, | ||
| 813 | update_graph_task_filter_callback); | ||
| 814 | } | ||
| 815 | |||
| 816 | static void | ||
| 817 | graph_hide_tasks_clicked (gpointer data) | ||
| 818 | { | ||
| 819 | struct shark_info *info = data; | ||
| 820 | struct graph_info *ginfo = info->ginfo; | ||
| 821 | |||
| 822 | __graph_tasks_clicked(info, ginfo->hide_tasks, | ||
| 823 | update_graph_hide_task_filter_callback); | ||
| 824 | } | ||
| 825 | |||
| 826 | /* Callback for the clicked signal of the Events filter button */ | ||
| 827 | static void | ||
| 828 | list_events_clicked (gpointer data) | ||
| 267 | { | 829 | { |
| 268 | struct shark_info *info = data; | 830 | struct shark_info *info = data; |
| 269 | struct event_filter *event_filter; | 831 | struct event_filter *event_filter; |
| @@ -281,13 +843,36 @@ sync_graph_events_to_list_clicked (gpointer data) | |||
| 281 | all_events = trace_view_store_get_all_events_enabled(store); | 843 | all_events = trace_view_store_get_all_events_enabled(store); |
| 282 | event_filter = trace_view_store_get_event_filter(store); | 844 | event_filter = trace_view_store_get_event_filter(store); |
| 283 | 845 | ||
| 284 | trace_graph_copy_filter(info->ginfo, all_events, | 846 | /* |
| 285 | event_filter); | 847 | * This menu is not available when in sync, so we |
| 848 | * can call the treeview callback directly. | ||
| 849 | */ | ||
| 850 | trace_filter_event_filter_dialog(store->handle, event_filter, | ||
| 851 | all_events, | ||
| 852 | trace_view_event_filter_callback, | ||
| 853 | info->treeview); | ||
| 286 | } | 854 | } |
| 287 | 855 | ||
| 856 | static void | ||
| 857 | graph_event_filter_callback(gboolean accept, | ||
| 858 | gboolean all_events, | ||
| 859 | gchar **systems, | ||
| 860 | gint *events, | ||
| 861 | gpointer data) | ||
| 862 | { | ||
| 863 | struct shark_info *info = data; | ||
| 864 | |||
| 865 | trace_graph_event_filter_callback(accept, all_events, | ||
| 866 | systems, events, | ||
| 867 | info->ginfo); | ||
| 868 | |||
| 869 | if (info->sync_event_filters) | ||
| 870 | trace_view_event_filter_callback(accept, all_events, systems, | ||
| 871 | events, info->treeview); | ||
| 872 | } | ||
| 288 | 873 | ||
| 289 | static void | 874 | static void |
| 290 | sync_list_events_to_graph_clicked (gpointer data) | 875 | graph_events_clicked (gpointer data) |
| 291 | { | 876 | { |
| 292 | struct shark_info *info = data; | 877 | struct shark_info *info = data; |
| 293 | struct graph_info *ginfo = info->ginfo; | 878 | struct graph_info *ginfo = info->ginfo; |
| @@ -295,8 +880,64 @@ sync_list_events_to_graph_clicked (gpointer data) | |||
| 295 | 880 | ||
| 296 | all_events = ginfo->all_events; | 881 | all_events = ginfo->all_events; |
| 297 | 882 | ||
| 298 | trace_view_copy_filter(info->treeview, all_events, | 883 | trace_filter_event_filter_dialog(info->handle, |
| 299 | ginfo->event_filter); | 884 | ginfo->event_filter, |
| 885 | all_events, | ||
| 886 | graph_event_filter_callback, | ||
| 887 | info); | ||
| 888 | } | ||
| 889 | |||
| 890 | /* Callback for the clicked signal of the List advanced filter button */ | ||
| 891 | static void | ||
| 892 | adv_list_filter_clicked (gpointer data) | ||
| 893 | { | ||
| 894 | struct shark_info *info = data; | ||
| 895 | struct event_filter *event_filter; | ||
| 896 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->treeview); | ||
| 897 | GtkTreeModel *model; | ||
| 898 | TraceViewStore *store; | ||
| 899 | |||
| 900 | model = gtk_tree_view_get_model(trace_tree); | ||
| 901 | if (!model) | ||
| 902 | return; | ||
| 903 | |||
| 904 | store = TRACE_VIEW_STORE(model); | ||
| 905 | |||
| 906 | event_filter = trace_view_store_get_event_filter(store); | ||
| 907 | |||
| 908 | /* | ||
| 909 | * This menu is not available when in sync, so we | ||
| 910 | * can call the treeview callback directly. | ||
| 911 | */ | ||
| 912 | trace_adv_filter_dialog(store->handle, event_filter, | ||
| 913 | trace_view_adv_filter_callback, trace_tree); | ||
| 914 | } | ||
| 915 | |||
| 916 | static void | ||
| 917 | graph_adv_filter_callback(gboolean accept, | ||
| 918 | const gchar *text, | ||
| 919 | gint *event_ids, | ||
| 920 | gpointer data) | ||
| 921 | { | ||
| 922 | struct shark_info *info = data; | ||
| 923 | struct graph_info *ginfo = info->ginfo; | ||
| 924 | |||
| 925 | trace_graph_adv_filter_callback(accept, text, event_ids, ginfo); | ||
| 926 | |||
| 927 | if (info->sync_event_filters) | ||
| 928 | trace_view_adv_filter_callback(accept, text, event_ids, | ||
| 929 | info->treeview); | ||
| 930 | } | ||
| 931 | |||
| 932 | /* Callback for the clicked signal of the Graph advanced filter button */ | ||
| 933 | static void | ||
| 934 | adv_graph_filter_clicked (gpointer data) | ||
| 935 | { | ||
| 936 | struct shark_info *info = data; | ||
| 937 | struct graph_info *ginfo = info->ginfo; | ||
| 938 | |||
| 939 | trace_adv_filter_dialog(ginfo->handle, ginfo->event_filter, | ||
| 940 | graph_adv_filter_callback, info); | ||
| 300 | } | 941 | } |
| 301 | 942 | ||
| 302 | /* Callback for the clicked signal of the CPUs filter button */ | 943 | /* Callback for the clicked signal of the CPUs filter button */ |
| @@ -362,6 +1003,34 @@ plot_tasks_clicked (gpointer data) | |||
| 362 | free(selected); | 1003 | free(selected); |
| 363 | } | 1004 | } |
| 364 | 1005 | ||
| 1006 | /* Callback for the clicked signal of the help contents button */ | ||
| 1007 | static void | ||
| 1008 | help_content_clicked (gpointer data) | ||
| 1009 | { | ||
| 1010 | struct shark_info *info = data; | ||
| 1011 | GError *error = NULL; | ||
| 1012 | gchar *link; | ||
| 1013 | |||
| 1014 | link = "file://" __stringify(HELP_DIR) "/index.html"; | ||
| 1015 | |||
| 1016 | trace_show_help(info->window, link, &error); | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | |||
| 1020 | /* Callback for the clicked signal of the help about button */ | ||
| 1021 | static void | ||
| 1022 | help_about_clicked (gpointer data) | ||
| 1023 | { | ||
| 1024 | struct shark_info *info = data; | ||
| 1025 | |||
| 1026 | trace_dialog(GTK_WINDOW(info->window), TRACE_GUI_INFO, | ||
| 1027 | "KernelShark\n\n" | ||
| 1028 | "version %s\n\n" | ||
| 1029 | "Copyright (C) 2009, 2010 Red Hat Inc\n\n" | ||
| 1030 | " Author: Steven Rostedt <srostedt@redhat.com>", | ||
| 1031 | VERSION_STRING); | ||
| 1032 | } | ||
| 1033 | |||
| 365 | static void graph_follows_tree(struct shark_info *info, | 1034 | static void graph_follows_tree(struct shark_info *info, |
| 366 | GtkTreeView *treeview, | 1035 | GtkTreeView *treeview, |
| 367 | GtkTreePath *path) | 1036 | GtkTreePath *path) |
| @@ -427,26 +1096,70 @@ static void | |||
| 427 | filter_list_enable_clicked (gpointer data) | 1096 | filter_list_enable_clicked (gpointer data) |
| 428 | { | 1097 | { |
| 429 | struct shark_info *info = data; | 1098 | struct shark_info *info = data; |
| 1099 | struct filter_task *task_filter; | ||
| 1100 | struct filter_task *hide_tasks; | ||
| 430 | 1101 | ||
| 431 | info->list_filter_enabled ^= 1; | 1102 | info->list_filter_enabled ^= 1; |
| 432 | 1103 | ||
| 1104 | if (info->sync_task_filters) { | ||
| 1105 | task_filter = info->ginfo->task_filter; | ||
| 1106 | hide_tasks = info->ginfo->hide_tasks; | ||
| 1107 | } else { | ||
| 1108 | task_filter = info->list_task_filter; | ||
| 1109 | hide_tasks = info->list_hide_tasks; | ||
| 1110 | } | ||
| 1111 | |||
| 433 | if (info->list_filter_enabled) | 1112 | if (info->list_filter_enabled) |
| 434 | trace_view_update_filters(info->treeview, | 1113 | trace_view_update_filters(info->treeview, |
| 435 | info->ginfo->task_filter, | 1114 | task_filter, hide_tasks); |
| 436 | info->ginfo->hide_tasks); | ||
| 437 | else | 1115 | else |
| 438 | trace_view_update_filters(info->treeview, NULL, NULL); | 1116 | trace_view_update_filters(info->treeview, NULL, NULL); |
| 439 | } | 1117 | } |
| 440 | 1118 | ||
| 441 | static void | 1119 | static void |
| 1120 | filter_update_list_filter(struct shark_info *info, | ||
| 1121 | struct filter_task *filter, | ||
| 1122 | struct filter_task *other_filter) | ||
| 1123 | { | ||
| 1124 | struct filter_task_item *task; | ||
| 1125 | int pid = info->selected_task; | ||
| 1126 | |||
| 1127 | task = filter_task_find_pid(filter, pid); | ||
| 1128 | if (task) { | ||
| 1129 | filter_task_remove_pid(filter, pid); | ||
| 1130 | if (!filter_task_count(filter) && | ||
| 1131 | !filter_task_count(other_filter)) { | ||
| 1132 | info->list_filter_enabled = 0; | ||
| 1133 | info->list_filter_available = 0; | ||
| 1134 | } | ||
| 1135 | } else { | ||
| 1136 | filter_task_add_pid(filter, pid); | ||
| 1137 | info->list_filter_available = 1; | ||
| 1138 | } | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | static void | ||
| 442 | filter_add_task_clicked (gpointer data) | 1142 | filter_add_task_clicked (gpointer data) |
| 443 | { | 1143 | { |
| 444 | struct shark_info *info = data; | 1144 | struct shark_info *info = data; |
| 1145 | int pid = info->selected_task; | ||
| 445 | 1146 | ||
| 446 | trace_graph_filter_add_remove_task(info->ginfo, info->selected_task); | 1147 | if (info->sync_task_filters) { |
| 1148 | trace_graph_filter_add_remove_task(info->ginfo, pid); | ||
| 1149 | return; | ||
| 1150 | } | ||
| 447 | 1151 | ||
| 448 | if (!filter_task_count(info->ginfo->task_filter)) | 1152 | filter_update_list_filter(info, info->list_task_filter, info->list_hide_tasks); |
| 449 | info->list_filter_enabled = 0; | 1153 | trace_view_update_filters(info->treeview, |
| 1154 | info->list_task_filter, info->list_hide_tasks); | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | static void | ||
| 1158 | filter_graph_add_task_clicked (gpointer data) | ||
| 1159 | { | ||
| 1160 | struct shark_info *info = data; | ||
| 1161 | |||
| 1162 | trace_graph_filter_add_remove_task(info->ginfo, info->selected_task); | ||
| 450 | } | 1163 | } |
| 451 | 1164 | ||
| 452 | static void | 1165 | static void |
| @@ -454,11 +1167,22 @@ filter_hide_task_clicked (gpointer data) | |||
| 454 | { | 1167 | { |
| 455 | struct shark_info *info = data; | 1168 | struct shark_info *info = data; |
| 456 | 1169 | ||
| 457 | trace_graph_filter_hide_show_task(info->ginfo, info->selected_task); | 1170 | if (info->sync_task_filters) { |
| 1171 | trace_graph_filter_hide_show_task(info->ginfo, info->selected_task); | ||
| 1172 | return; | ||
| 1173 | } | ||
| 458 | 1174 | ||
| 459 | if (!filter_task_count(info->ginfo->task_filter) && | 1175 | filter_update_list_filter(info, info->list_hide_tasks, info->list_task_filter); |
| 460 | !filter_task_count(info->ginfo->hide_tasks)) | 1176 | trace_view_update_filters(info->treeview, |
| 461 | info->list_filter_enabled = 0; | 1177 | info->list_task_filter, info->list_hide_tasks); |
| 1178 | } | ||
| 1179 | |||
| 1180 | static void | ||
| 1181 | filter_graph_hide_task_clicked (gpointer data) | ||
| 1182 | { | ||
| 1183 | struct shark_info *info = data; | ||
| 1184 | |||
| 1185 | trace_graph_filter_hide_show_task(info->ginfo, info->selected_task); | ||
| 462 | } | 1186 | } |
| 463 | 1187 | ||
| 464 | static void | 1188 | static void |
| @@ -466,11 +1190,27 @@ filter_clear_tasks_clicked (gpointer data) | |||
| 466 | { | 1190 | { |
| 467 | struct shark_info *info = data; | 1191 | struct shark_info *info = data; |
| 468 | 1192 | ||
| 469 | trace_graph_clear_tasks(info->ginfo); | 1193 | if (info->sync_task_filters) { |
| 1194 | trace_graph_clear_tasks(info->ginfo); | ||
| 1195 | return; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | filter_task_clear(info->list_task_filter); | ||
| 1199 | filter_task_clear(info->list_hide_tasks); | ||
| 1200 | trace_view_update_filters(info->treeview, NULL, NULL); | ||
| 470 | 1201 | ||
| 1202 | info->list_filter_available = 0; | ||
| 471 | info->list_filter_enabled = 0; | 1203 | info->list_filter_enabled = 0; |
| 472 | } | 1204 | } |
| 473 | 1205 | ||
| 1206 | static void | ||
| 1207 | filter_graph_clear_tasks_clicked (gpointer data) | ||
| 1208 | { | ||
| 1209 | struct shark_info *info = data; | ||
| 1210 | |||
| 1211 | trace_graph_clear_tasks(info->ginfo); | ||
| 1212 | } | ||
| 1213 | |||
| 474 | static void graph_check_toggle(gpointer data, GtkWidget *widget) | 1214 | static void graph_check_toggle(gpointer data, GtkWidget *widget) |
| 475 | { | 1215 | { |
| 476 | struct shark_info *info = data; | 1216 | struct shark_info *info = data; |
| @@ -478,6 +1218,17 @@ static void graph_check_toggle(gpointer data, GtkWidget *widget) | |||
| 478 | info->graph_follows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); | 1218 | info->graph_follows = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); |
| 479 | } | 1219 | } |
| 480 | 1220 | ||
| 1221 | static void set_menu_label(GtkWidget *menu, const char *comm, int pid, | ||
| 1222 | const char *fmt) | ||
| 1223 | { | ||
| 1224 | int len = strlen(comm) + strlen(fmt) + 50; | ||
| 1225 | char text[len]; | ||
| 1226 | |||
| 1227 | snprintf(text, len, fmt, comm, pid); | ||
| 1228 | |||
| 1229 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu), text); | ||
| 1230 | } | ||
| 1231 | |||
| 481 | static gboolean | 1232 | static gboolean |
| 482 | do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | 1233 | do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) |
| 483 | { | 1234 | { |
| @@ -489,11 +1240,13 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 489 | static GtkWidget *menu_filter_add_task; | 1240 | static GtkWidget *menu_filter_add_task; |
| 490 | static GtkWidget *menu_filter_hide_task; | 1241 | static GtkWidget *menu_filter_hide_task; |
| 491 | static GtkWidget *menu_filter_clear_tasks; | 1242 | static GtkWidget *menu_filter_clear_tasks; |
| 1243 | static GtkWidget *menu_filter_graph_add_task; | ||
| 1244 | static GtkWidget *menu_filter_graph_hide_task; | ||
| 1245 | static GtkWidget *menu_filter_graph_clear_tasks; | ||
| 492 | struct record *record; | 1246 | struct record *record; |
| 493 | TraceViewRecord *vrec; | 1247 | TraceViewRecord *vrec; |
| 494 | GtkTreeModel *model; | 1248 | GtkTreeModel *model; |
| 495 | const char *comm; | 1249 | const char *comm; |
| 496 | gchar *text; | ||
| 497 | gint pid; | 1250 | gint pid; |
| 498 | gint len; | 1251 | gint len; |
| 499 | guint64 offset; | 1252 | guint64 offset; |
| @@ -502,7 +1255,7 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 502 | 1255 | ||
| 503 | if (!menu) { | 1256 | if (!menu) { |
| 504 | menu = gtk_menu_new(); | 1257 | menu = gtk_menu_new(); |
| 505 | menu_filter_graph_enable = gtk_menu_item_new_with_label("Enable Graph Filter"); | 1258 | menu_filter_graph_enable = gtk_menu_item_new_with_label("Enable Graph Task Filter"); |
| 506 | gtk_widget_show(menu_filter_graph_enable); | 1259 | gtk_widget_show(menu_filter_graph_enable); |
| 507 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_enable); | 1260 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_enable); |
| 508 | 1261 | ||
| @@ -510,7 +1263,7 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 510 | G_CALLBACK (filter_graph_enable_clicked), | 1263 | G_CALLBACK (filter_graph_enable_clicked), |
| 511 | data); | 1264 | data); |
| 512 | 1265 | ||
| 513 | menu_filter_list_enable = gtk_menu_item_new_with_label("Enable List Filter"); | 1266 | menu_filter_list_enable = gtk_menu_item_new_with_label("Enable List Task Filter"); |
| 514 | gtk_widget_show(menu_filter_list_enable); | 1267 | gtk_widget_show(menu_filter_list_enable); |
| 515 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_list_enable); | 1268 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_list_enable); |
| 516 | 1269 | ||
| @@ -526,6 +1279,14 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 526 | G_CALLBACK (filter_add_task_clicked), | 1279 | G_CALLBACK (filter_add_task_clicked), |
| 527 | data); | 1280 | data); |
| 528 | 1281 | ||
| 1282 | menu_filter_graph_add_task = gtk_menu_item_new_with_label("Add Task to Graph"); | ||
| 1283 | gtk_widget_show(menu_filter_graph_add_task); | ||
| 1284 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_add_task); | ||
| 1285 | |||
| 1286 | g_signal_connect_swapped (G_OBJECT (menu_filter_graph_add_task), "activate", | ||
| 1287 | G_CALLBACK (filter_graph_add_task_clicked), | ||
| 1288 | data); | ||
| 1289 | |||
| 529 | menu_filter_hide_task = gtk_menu_item_new_with_label("Hide Task"); | 1290 | menu_filter_hide_task = gtk_menu_item_new_with_label("Hide Task"); |
| 530 | gtk_widget_show(menu_filter_hide_task); | 1291 | gtk_widget_show(menu_filter_hide_task); |
| 531 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_hide_task); | 1292 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_hide_task); |
| @@ -534,6 +1295,14 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 534 | G_CALLBACK (filter_hide_task_clicked), | 1295 | G_CALLBACK (filter_hide_task_clicked), |
| 535 | data); | 1296 | data); |
| 536 | 1297 | ||
| 1298 | menu_filter_graph_hide_task = gtk_menu_item_new_with_label("Hide Task from Graph"); | ||
| 1299 | gtk_widget_show(menu_filter_graph_hide_task); | ||
| 1300 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_hide_task); | ||
| 1301 | |||
| 1302 | g_signal_connect_swapped (G_OBJECT (menu_filter_graph_hide_task), "activate", | ||
| 1303 | G_CALLBACK (filter_graph_hide_task_clicked), | ||
| 1304 | data); | ||
| 1305 | |||
| 537 | menu_filter_clear_tasks = gtk_menu_item_new_with_label("Clear Task Filter"); | 1306 | menu_filter_clear_tasks = gtk_menu_item_new_with_label("Clear Task Filter"); |
| 538 | gtk_widget_show(menu_filter_clear_tasks); | 1307 | gtk_widget_show(menu_filter_clear_tasks); |
| 539 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_clear_tasks); | 1308 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_clear_tasks); |
| @@ -542,6 +1311,15 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 542 | G_CALLBACK (filter_clear_tasks_clicked), | 1311 | G_CALLBACK (filter_clear_tasks_clicked), |
| 543 | data); | 1312 | data); |
| 544 | 1313 | ||
| 1314 | menu_filter_graph_clear_tasks = | ||
| 1315 | gtk_menu_item_new_with_label("Clear Graph Task Filter"); | ||
| 1316 | gtk_widget_show(menu_filter_graph_clear_tasks); | ||
| 1317 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_graph_clear_tasks); | ||
| 1318 | |||
| 1319 | g_signal_connect_swapped (G_OBJECT (menu_filter_graph_clear_tasks), "activate", | ||
| 1320 | G_CALLBACK (filter_graph_clear_tasks_clicked), | ||
| 1321 | data); | ||
| 1322 | |||
| 545 | } | 1323 | } |
| 546 | 1324 | ||
| 547 | row = trace_view_get_selected_row(GTK_WIDGET(info->treeview)); | 1325 | row = trace_view_get_selected_row(GTK_WIDGET(info->treeview)); |
| @@ -559,29 +1337,59 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 559 | 1337 | ||
| 560 | len = strlen(comm) + 50; | 1338 | len = strlen(comm) + 50; |
| 561 | 1339 | ||
| 562 | text = g_malloc(len); | 1340 | if (info->sync_task_filters) { |
| 563 | g_assert(text); | 1341 | if (trace_graph_filter_task_find_pid(ginfo, pid)) |
| 564 | 1342 | set_menu_label(menu_filter_add_task, comm, pid, | |
| 565 | if (trace_graph_filter_task_find_pid(ginfo, pid)) | 1343 | "Remove %s-%d from filters"); |
| 566 | snprintf(text, len, "Remove %s-%d to filter", comm, pid); | 1344 | else |
| 567 | else | 1345 | set_menu_label(menu_filter_add_task, comm, pid, |
| 568 | snprintf(text, len, "Add %s-%d to filter", comm, pid); | 1346 | "Add %s-%d to filters"); |
| 1347 | |||
| 1348 | if (trace_graph_hide_task_find_pid(ginfo, pid)) | ||
| 1349 | set_menu_label(menu_filter_hide_task, comm, pid, | ||
| 1350 | "Show %s-%d"); | ||
| 1351 | else | ||
| 1352 | set_menu_label(menu_filter_hide_task, comm, pid, | ||
| 1353 | "Hide %s-%d"); | ||
| 1354 | |||
| 1355 | gtk_widget_hide(menu_filter_graph_add_task); | ||
| 1356 | gtk_widget_hide(menu_filter_graph_hide_task); | ||
| 1357 | |||
| 1358 | } else { | ||
| 1359 | if (filter_task_find_pid(info->list_task_filter, pid)) | ||
| 1360 | set_menu_label(menu_filter_add_task, comm, pid, | ||
| 1361 | "Remove %s-%d from List filter"); | ||
| 1362 | else | ||
| 1363 | set_menu_label(menu_filter_add_task, comm, pid, | ||
| 1364 | "Add %s-%d to List filter"); | ||
| 1365 | |||
| 1366 | if (filter_task_find_pid(info->list_hide_tasks, pid)) | ||
| 1367 | set_menu_label(menu_filter_hide_task, comm, pid, | ||
| 1368 | "Show %s-%d in List"); | ||
| 1369 | else | ||
| 1370 | set_menu_label(menu_filter_hide_task, comm, pid, | ||
| 1371 | "Hide %s-%d from List"); | ||
| 1372 | |||
| 1373 | if (trace_graph_filter_task_find_pid(ginfo, pid)) | ||
| 1374 | set_menu_label(menu_filter_graph_add_task, comm, pid, | ||
| 1375 | "Remove %s-%d from Graph filter"); | ||
| 1376 | else | ||
| 1377 | set_menu_label(menu_filter_graph_add_task, comm, pid, | ||
| 1378 | "Add %s-%d to Graph filter"); | ||
| 1379 | |||
| 1380 | if (trace_graph_hide_task_find_pid(ginfo, pid)) | ||
| 1381 | set_menu_label(menu_filter_graph_hide_task, comm, pid, | ||
| 1382 | "Show %s-%d in Graph"); | ||
| 1383 | else | ||
| 1384 | set_menu_label(menu_filter_graph_hide_task, comm, pid, | ||
| 1385 | "Hide %s-%d from Graph"); | ||
| 1386 | |||
| 1387 | gtk_widget_show(menu_filter_graph_add_task); | ||
| 1388 | gtk_widget_show(menu_filter_graph_hide_task); | ||
| 1389 | } | ||
| 569 | 1390 | ||
| 570 | ginfo->filter_task_selected = pid; | 1391 | ginfo->filter_task_selected = pid; |
| 571 | 1392 | ||
| 572 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_add_task), | ||
| 573 | text); | ||
| 574 | |||
| 575 | if (trace_graph_hide_task_find_pid(ginfo, pid)) | ||
| 576 | snprintf(text, len, "Show %s-%d", comm, pid); | ||
| 577 | else | ||
| 578 | snprintf(text, len, "Hide %s-%d", comm, pid); | ||
| 579 | |||
| 580 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_hide_task), | ||
| 581 | text); | ||
| 582 | |||
| 583 | g_free(text); | ||
| 584 | |||
| 585 | info->selected_task = pid; | 1393 | info->selected_task = pid; |
| 586 | 1394 | ||
| 587 | gtk_widget_show(menu_filter_add_task); | 1395 | gtk_widget_show(menu_filter_add_task); |
| @@ -591,35 +1399,62 @@ do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 591 | } else { | 1399 | } else { |
| 592 | gtk_widget_hide(menu_filter_add_task); | 1400 | gtk_widget_hide(menu_filter_add_task); |
| 593 | gtk_widget_hide(menu_filter_hide_task); | 1401 | gtk_widget_hide(menu_filter_hide_task); |
| 1402 | gtk_widget_hide(menu_filter_graph_add_task); | ||
| 1403 | gtk_widget_hide(menu_filter_graph_hide_task); | ||
| 594 | } | 1404 | } |
| 595 | 1405 | ||
| 596 | if (ginfo->filter_enabled) | 1406 | if (ginfo->filter_enabled) |
| 597 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable), | 1407 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable), |
| 598 | "Disable Graph Filter"); | 1408 | "Disable Graph Task Filter"); |
| 599 | else | 1409 | else |
| 600 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable), | 1410 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_graph_enable), |
| 601 | "Enable Graph Filter"); | 1411 | "Enable Graph Task Filter"); |
| 602 | 1412 | ||
| 603 | if (info->list_filter_enabled) | 1413 | if (info->list_filter_enabled) |
| 604 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable), | 1414 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable), |
| 605 | "Disable List Filter"); | 1415 | "Disable List Task Filter"); |
| 606 | else | 1416 | else |
| 607 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable), | 1417 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_list_enable), |
| 608 | "Enable List Filter"); | 1418 | "Enable List Task Filter"); |
| 609 | 1419 | ||
| 610 | if (ginfo->filter_available) { | 1420 | if (ginfo->filter_available) |
| 611 | gtk_widget_set_sensitive(menu_filter_graph_enable, TRUE); | 1421 | gtk_widget_set_sensitive(menu_filter_graph_enable, TRUE); |
| 612 | gtk_widget_set_sensitive(menu_filter_list_enable, TRUE); | 1422 | else |
| 613 | } else { | ||
| 614 | gtk_widget_set_sensitive(menu_filter_graph_enable, FALSE); | 1423 | gtk_widget_set_sensitive(menu_filter_graph_enable, FALSE); |
| 615 | gtk_widget_set_sensitive(menu_filter_list_enable, FALSE); | ||
| 616 | } | ||
| 617 | 1424 | ||
| 618 | if (filter_task_count(ginfo->task_filter) || | 1425 | if ((info->sync_task_filters && ginfo->filter_available) || |
| 619 | filter_task_count(ginfo->hide_tasks)) | 1426 | (!info->sync_task_filters && info->list_filter_available)) |
| 620 | gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE); | 1427 | gtk_widget_set_sensitive(menu_filter_list_enable, TRUE); |
| 621 | else | 1428 | else |
| 622 | gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE); | 1429 | gtk_widget_set_sensitive(menu_filter_list_enable, FALSE); |
| 1430 | |||
| 1431 | if (info->sync_task_filters) { | ||
| 1432 | if (filter_task_count(ginfo->task_filter) || | ||
| 1433 | filter_task_count(ginfo->hide_tasks)) | ||
| 1434 | gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE); | ||
| 1435 | else | ||
| 1436 | gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE); | ||
| 1437 | |||
| 1438 | set_menu_label(menu_filter_clear_tasks, comm, pid, | ||
| 1439 | "Clear Task Filter"); | ||
| 1440 | gtk_widget_hide(menu_filter_graph_clear_tasks); | ||
| 1441 | } else { | ||
| 1442 | if (filter_task_count(ginfo->task_filter) || | ||
| 1443 | filter_task_count(ginfo->hide_tasks)) | ||
| 1444 | gtk_widget_set_sensitive(menu_filter_graph_clear_tasks, TRUE); | ||
| 1445 | else | ||
| 1446 | gtk_widget_set_sensitive(menu_filter_graph_clear_tasks, FALSE); | ||
| 1447 | |||
| 1448 | if (filter_task_count(info->list_task_filter) || | ||
| 1449 | filter_task_count(info->list_hide_tasks)) | ||
| 1450 | gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE); | ||
| 1451 | else | ||
| 1452 | gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE); | ||
| 1453 | |||
| 1454 | set_menu_label(menu_filter_clear_tasks, comm, pid, | ||
| 1455 | "Clear List Task Filter"); | ||
| 1456 | gtk_widget_show(menu_filter_graph_clear_tasks); | ||
| 1457 | } | ||
| 623 | 1458 | ||
| 624 | gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, | 1459 | gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, |
| 625 | gtk_get_current_event_time()); | 1460 | gtk_get_current_event_time()); |
| @@ -655,6 +1490,7 @@ void kernel_shark(int argc, char **argv) | |||
| 655 | GtkWidget *label; | 1490 | GtkWidget *label; |
| 656 | GtkWidget *spin; | 1491 | GtkWidget *spin; |
| 657 | GtkWidget *check; | 1492 | GtkWidget *check; |
| 1493 | GtkWidget *statusbar; | ||
| 658 | int ret; | 1494 | int ret; |
| 659 | int c; | 1495 | int c; |
| 660 | 1496 | ||
| @@ -701,12 +1537,16 @@ void kernel_shark(int argc, char **argv) | |||
| 701 | handle = NULL; | 1537 | handle = NULL; |
| 702 | 1538 | ||
| 703 | info->handle = handle; | 1539 | info->handle = handle; |
| 1540 | info->sync_task_filters = TRUE; | ||
| 1541 | info->sync_event_filters = TRUE; | ||
| 704 | 1542 | ||
| 705 | /* --- Main window --- */ | 1543 | /* --- Main window --- */ |
| 706 | 1544 | ||
| 707 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | 1545 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
| 708 | info->window = window; | 1546 | info->window = window; |
| 709 | 1547 | ||
| 1548 | trace_dialog_register_window(window); | ||
| 1549 | |||
| 710 | if (input_file) | 1550 | if (input_file) |
| 711 | update_title(window, input_file); | 1551 | update_title(window, input_file); |
| 712 | 1552 | ||
| @@ -734,12 +1574,11 @@ void kernel_shark(int argc, char **argv) | |||
| 734 | 1574 | ||
| 735 | /* --- File - Load Option --- */ | 1575 | /* --- File - Load Option --- */ |
| 736 | 1576 | ||
| 737 | sub_item = gtk_menu_item_new_with_label("Load info"); | 1577 | sub_item = gtk_menu_item_new_with_label("Load data"); |
| 738 | 1578 | ||
| 739 | /* Add them to the menu */ | 1579 | /* Add them to the menu */ |
| 740 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 1580 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
| 741 | 1581 | ||
| 742 | /* We can attach the Quit menu item to our exit function */ | ||
| 743 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | 1582 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", |
| 744 | G_CALLBACK (load_clicked), | 1583 | G_CALLBACK (load_clicked), |
| 745 | (gpointer) info); | 1584 | (gpointer) info); |
| @@ -748,6 +1587,35 @@ void kernel_shark(int argc, char **argv) | |||
| 748 | gtk_widget_show(sub_item); | 1587 | gtk_widget_show(sub_item); |
| 749 | 1588 | ||
| 750 | 1589 | ||
| 1590 | /* --- File - Load Filter Option --- */ | ||
| 1591 | |||
| 1592 | sub_item = gtk_menu_item_new_with_label("Load filters"); | ||
| 1593 | |||
| 1594 | /* Add them to the menu */ | ||
| 1595 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 1596 | |||
| 1597 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 1598 | G_CALLBACK (load_filters_clicked), | ||
| 1599 | (gpointer) info); | ||
| 1600 | |||
| 1601 | /* We do need to show menu items */ | ||
| 1602 | gtk_widget_show(sub_item); | ||
| 1603 | |||
| 1604 | |||
| 1605 | /* --- File - Save Filter Option --- */ | ||
| 1606 | |||
| 1607 | sub_item = gtk_menu_item_new_with_label("Save filters"); | ||
| 1608 | |||
| 1609 | /* Add them to the menu */ | ||
| 1610 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 1611 | |||
| 1612 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 1613 | G_CALLBACK (save_filters_clicked), | ||
| 1614 | (gpointer) info); | ||
| 1615 | |||
| 1616 | /* We do need to show menu items */ | ||
| 1617 | gtk_widget_show(sub_item); | ||
| 1618 | |||
| 751 | /* --- File - Quit Option --- */ | 1619 | /* --- File - Quit Option --- */ |
| 752 | 1620 | ||
| 753 | sub_item = gtk_menu_item_new_with_label("Quit"); | 1621 | sub_item = gtk_menu_item_new_with_label("Quit"); |
| @@ -777,66 +1645,145 @@ void kernel_shark(int argc, char **argv) | |||
| 777 | menu = gtk_menu_new(); /* Don't need to show menus */ | 1645 | menu = gtk_menu_new(); /* Don't need to show menus */ |
| 778 | 1646 | ||
| 779 | 1647 | ||
| 780 | /* --- Filter - List Events Option --- */ | ||
| 781 | 1648 | ||
| 782 | sub_item = gtk_menu_item_new_with_label("list events"); | 1649 | /* --- Filter - Sync task Option --- */ |
| 1650 | |||
| 1651 | sub_item = gtk_menu_item_new_with_label("Unsync Graph and List Task Filters"); | ||
| 1652 | |||
| 1653 | info->task_sync_menu = sub_item; | ||
| 783 | 1654 | ||
| 784 | /* Add them to the menu */ | 1655 | /* Add them to the menu */ |
| 785 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 1656 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
| 786 | 1657 | ||
| 787 | /* We can attach the Quit menu item to our exit function */ | 1658 | /* We can attach the Quit menu item to our exit function */ |
| 788 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | 1659 | g_signal_connect (G_OBJECT (sub_item), "activate", |
| 789 | G_CALLBACK (list_events_clicked), | 1660 | G_CALLBACK (sync_task_filter_clicked), |
| 790 | (gpointer) info); | 1661 | (gpointer) info); |
| 791 | 1662 | ||
| 792 | /* We do need to show menu items */ | 1663 | /* We do need to show menu items */ |
| 793 | gtk_widget_show(sub_item); | 1664 | gtk_widget_show(sub_item); |
| 794 | 1665 | ||
| 795 | 1666 | ||
| 796 | /* --- Filter - Events Option --- */ | 1667 | /* --- Filter - Sync events Option --- */ |
| 1668 | |||
| 1669 | sub_item = gtk_menu_item_new_with_label("Unsync Graph and List Event Filters"); | ||
| 797 | 1670 | ||
| 798 | sub_item = gtk_menu_item_new_with_label("graph events"); | 1671 | info->events_sync_menu = sub_item; |
| 1672 | |||
| 1673 | /* Add them to the menu */ | ||
| 1674 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 1675 | |||
| 1676 | /* We can attach the Quit menu item to our exit function */ | ||
| 1677 | g_signal_connect (G_OBJECT (sub_item), "activate", | ||
| 1678 | G_CALLBACK (sync_events_filter_clicked), | ||
| 1679 | (gpointer) info); | ||
| 1680 | |||
| 1681 | /* We do need to show menu items */ | ||
| 1682 | gtk_widget_show(sub_item); | ||
| 1683 | |||
| 1684 | |||
| 1685 | /* --- Filter - List Tasks Option --- */ | ||
| 1686 | |||
| 1687 | sub_item = gtk_menu_item_new_with_label("list tasks"); | ||
| 799 | 1688 | ||
| 800 | /* Add them to the menu */ | 1689 | /* Add them to the menu */ |
| 801 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 1690 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
| 802 | 1691 | ||
| 803 | /* We can attach the Quit menu item to our exit function */ | 1692 | /* We can attach the Quit menu item to our exit function */ |
| 804 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | 1693 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", |
| 805 | G_CALLBACK (graph_events_clicked), | 1694 | G_CALLBACK (list_tasks_clicked), |
| 1695 | (gpointer) info); | ||
| 1696 | |||
| 1697 | info->list_task_menu = sub_item; | ||
| 1698 | |||
| 1699 | /* Only show this item when list and graph tasks are not synced */ | ||
| 1700 | |||
| 1701 | |||
| 1702 | /* --- Filter - Graph Tasks Option --- */ | ||
| 1703 | |||
| 1704 | sub_item = gtk_menu_item_new_with_label("tasks"); | ||
| 1705 | |||
| 1706 | /* Add them to the menu */ | ||
| 1707 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 1708 | |||
| 1709 | /* We can attach the Quit menu item to our exit function */ | ||
| 1710 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 1711 | G_CALLBACK (graph_tasks_clicked), | ||
| 806 | (gpointer) info); | 1712 | (gpointer) info); |
| 807 | 1713 | ||
| 1714 | info->graph_task_menu = sub_item; | ||
| 1715 | |||
| 808 | /* We do need to show menu items */ | 1716 | /* We do need to show menu items */ |
| 809 | gtk_widget_show(sub_item); | 1717 | gtk_widget_show(sub_item); |
| 810 | 1718 | ||
| 811 | 1719 | ||
| 812 | /* --- Filter - Events Option --- */ | 1720 | /* --- Filter - List Hide Tasks Option --- */ |
| 813 | 1721 | ||
| 814 | sub_item = gtk_menu_item_new_with_label("sync graph events with list"); | 1722 | sub_item = gtk_menu_item_new_with_label("list hide tasks"); |
| 815 | 1723 | ||
| 816 | /* Add them to the menu */ | 1724 | /* Add them to the menu */ |
| 817 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 1725 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
| 818 | 1726 | ||
| 819 | /* We can attach the Quit menu item to our exit function */ | 1727 | /* We can attach the Quit menu item to our exit function */ |
| 820 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | 1728 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", |
| 821 | G_CALLBACK (sync_graph_events_to_list_clicked), | 1729 | G_CALLBACK (list_hide_tasks_clicked), |
| 822 | (gpointer) info); | 1730 | (gpointer) info); |
| 823 | 1731 | ||
| 1732 | info->list_hide_task_menu = sub_item; | ||
| 1733 | |||
| 1734 | /* Only show this item when list and graph tasks are not synced */ | ||
| 1735 | |||
| 1736 | |||
| 1737 | /* --- Filter - Graph Hide Tasks Option --- */ | ||
| 1738 | |||
| 1739 | sub_item = gtk_menu_item_new_with_label("hide tasks"); | ||
| 1740 | |||
| 1741 | /* Add them to the menu */ | ||
| 1742 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 1743 | |||
| 1744 | /* We can attach the Quit menu item to our exit function */ | ||
| 1745 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 1746 | G_CALLBACK (graph_hide_tasks_clicked), | ||
| 1747 | (gpointer) info); | ||
| 1748 | |||
| 1749 | info->graph_hide_task_menu = sub_item; | ||
| 1750 | |||
| 824 | /* We do need to show menu items */ | 1751 | /* We do need to show menu items */ |
| 825 | gtk_widget_show(sub_item); | 1752 | gtk_widget_show(sub_item); |
| 826 | 1753 | ||
| 827 | 1754 | ||
| 1755 | /* --- Filter - List Events Option --- */ | ||
| 1756 | |||
| 1757 | sub_item = gtk_menu_item_new_with_label("list events"); | ||
| 1758 | |||
| 1759 | /* Add them to the menu */ | ||
| 1760 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 1761 | |||
| 1762 | /* We can attach the Quit menu item to our exit function */ | ||
| 1763 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 1764 | G_CALLBACK (list_events_clicked), | ||
| 1765 | (gpointer) info); | ||
| 1766 | |||
| 1767 | info->list_events_menu = sub_item; | ||
| 1768 | |||
| 1769 | /* We do not show this menu (yet) */ | ||
| 1770 | |||
| 1771 | |||
| 828 | /* --- Filter - Events Option --- */ | 1772 | /* --- Filter - Events Option --- */ |
| 829 | 1773 | ||
| 830 | sub_item = gtk_menu_item_new_with_label("sync list events with graph"); | 1774 | /* The list and graph events start off insync */ |
| 1775 | sub_item = gtk_menu_item_new_with_label("events"); | ||
| 831 | 1776 | ||
| 832 | /* Add them to the menu */ | 1777 | /* Add them to the menu */ |
| 833 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 1778 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
| 834 | 1779 | ||
| 835 | /* We can attach the Quit menu item to our exit function */ | 1780 | /* We can attach the Quit menu item to our exit function */ |
| 836 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | 1781 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", |
| 837 | G_CALLBACK (sync_list_events_to_graph_clicked), | 1782 | G_CALLBACK (graph_events_clicked), |
| 838 | (gpointer) info); | 1783 | (gpointer) info); |
| 839 | 1784 | ||
| 1785 | info->graph_events_menu = sub_item; | ||
| 1786 | |||
| 840 | /* We do need to show menu items */ | 1787 | /* We do need to show menu items */ |
| 841 | gtk_widget_show(sub_item); | 1788 | gtk_widget_show(sub_item); |
| 842 | 1789 | ||
| @@ -853,13 +1800,14 @@ void kernel_shark(int argc, char **argv) | |||
| 853 | G_CALLBACK (adv_list_filter_clicked), | 1800 | G_CALLBACK (adv_list_filter_clicked), |
| 854 | (gpointer) info); | 1801 | (gpointer) info); |
| 855 | 1802 | ||
| 856 | /* We do need to show menu items */ | 1803 | info->list_adv_events_menu = sub_item; |
| 857 | gtk_widget_show(sub_item); | 1804 | /* We do not show this menu (yet) */ |
| 858 | 1805 | ||
| 859 | 1806 | ||
| 860 | /* --- Filter - Graph Advanced Events Option --- */ | 1807 | /* --- Filter - Graph Advanced Events Option --- */ |
| 861 | 1808 | ||
| 862 | sub_item = gtk_menu_item_new_with_label("graph advanced event"); | 1809 | /* The list and graph events start off in sync */ |
| 1810 | sub_item = gtk_menu_item_new_with_label("advanced events"); | ||
| 863 | 1811 | ||
| 864 | /* Add them to the menu */ | 1812 | /* Add them to the menu */ |
| 865 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 1813 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
| @@ -869,6 +1817,8 @@ void kernel_shark(int argc, char **argv) | |||
| 869 | G_CALLBACK (adv_graph_filter_clicked), | 1817 | G_CALLBACK (adv_graph_filter_clicked), |
| 870 | (gpointer) info); | 1818 | (gpointer) info); |
| 871 | 1819 | ||
| 1820 | info->graph_adv_events_menu = sub_item; | ||
| 1821 | |||
| 872 | /* We do need to show menu items */ | 1822 | /* We do need to show menu items */ |
| 873 | gtk_widget_show(sub_item); | 1823 | gtk_widget_show(sub_item); |
| 874 | 1824 | ||
| @@ -939,6 +1889,53 @@ void kernel_shark(int argc, char **argv) | |||
| 939 | gtk_menu_item_set_submenu(GTK_MENU_ITEM (menu_item), menu); | 1889 | gtk_menu_item_set_submenu(GTK_MENU_ITEM (menu_item), menu); |
| 940 | 1890 | ||
| 941 | 1891 | ||
| 1892 | |||
| 1893 | /* --- Help Option --- */ | ||
| 1894 | |||
| 1895 | menu_item = gtk_menu_item_new_with_label("Help"); | ||
| 1896 | gtk_widget_show(menu_item); | ||
| 1897 | |||
| 1898 | gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), menu_item); | ||
| 1899 | |||
| 1900 | menu = gtk_menu_new(); /* Don't need to show menus */ | ||
| 1901 | |||
| 1902 | |||
| 1903 | /* --- Help - Contents Option --- */ | ||
| 1904 | |||
| 1905 | sub_item = gtk_menu_item_new_with_label("Contents"); | ||
| 1906 | |||
| 1907 | /* Add them to the menu */ | ||
| 1908 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 1909 | |||
| 1910 | /* We can attach the Quit menu item to our exit function */ | ||
| 1911 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 1912 | G_CALLBACK (help_content_clicked), | ||
| 1913 | (gpointer) info); | ||
| 1914 | |||
| 1915 | /* We do need to show menu items */ | ||
| 1916 | gtk_widget_show(sub_item); | ||
| 1917 | |||
| 1918 | |||
| 1919 | /* --- Help - About Option --- */ | ||
| 1920 | |||
| 1921 | sub_item = gtk_menu_item_new_with_label("About"); | ||
| 1922 | |||
| 1923 | /* Add them to the menu */ | ||
| 1924 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 1925 | |||
| 1926 | /* We can attach the Quit menu item to our exit function */ | ||
| 1927 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 1928 | G_CALLBACK (help_about_clicked), | ||
| 1929 | (gpointer) info); | ||
| 1930 | |||
| 1931 | /* We do need to show menu items */ | ||
| 1932 | gtk_widget_show(sub_item); | ||
| 1933 | |||
| 1934 | |||
| 1935 | /* --- End Help Options --- */ | ||
| 1936 | gtk_menu_item_set_submenu(GTK_MENU_ITEM (menu_item), menu); | ||
| 1937 | |||
| 1938 | |||
| 942 | /* --- Top Level Vpaned --- */ | 1939 | /* --- Top Level Vpaned --- */ |
| 943 | 1940 | ||
| 944 | vpaned = gtk_vpaned_new(); | 1941 | vpaned = gtk_vpaned_new(); |
| @@ -1033,6 +2030,12 @@ void kernel_shark(int argc, char **argv) | |||
| 1033 | 2030 | ||
| 1034 | gtk_widget_show(info->treeview); | 2031 | gtk_widget_show(info->treeview); |
| 1035 | 2032 | ||
| 2033 | /* --- Set up Status Bar --- */ | ||
| 2034 | |||
| 2035 | statusbar = trace_status_bar_new(); | ||
| 2036 | |||
| 2037 | gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); | ||
| 2038 | gtk_widget_show(statusbar); | ||
| 1036 | 2039 | ||
| 1037 | /********************************************** | 2040 | /********************************************** |
| 1038 | * Main Window | 2041 | * Main Window |
diff --git a/kernel-shark.h b/kernel-shark.h index edb3787..a808108 100644 --- a/kernel-shark.h +++ b/kernel-shark.h | |||
| @@ -30,10 +30,25 @@ struct shark_info { | |||
| 30 | struct tracecmd_input *handle; | 30 | struct tracecmd_input *handle; |
| 31 | GtkWidget *treeview; | 31 | GtkWidget *treeview; |
| 32 | GtkWidget *spin; | 32 | GtkWidget *spin; |
| 33 | GtkWidget *task_sync_menu; | ||
| 34 | GtkWidget *events_sync_menu; | ||
| 35 | GtkWidget *list_task_menu; | ||
| 36 | GtkWidget *graph_task_menu; | ||
| 37 | GtkWidget *list_hide_task_menu; | ||
| 38 | GtkWidget *graph_hide_task_menu; | ||
| 39 | GtkWidget *list_events_menu; | ||
| 40 | GtkWidget *graph_events_menu; | ||
| 41 | GtkWidget *list_adv_events_menu; | ||
| 42 | GtkWidget *graph_adv_events_menu; | ||
| 33 | struct graph_callbacks graph_cbs; | 43 | struct graph_callbacks graph_cbs; |
| 34 | gint selected_task; | 44 | gint selected_task; |
| 35 | gboolean list_filter_enabled; | 45 | gboolean list_filter_enabled; |
| 46 | gboolean list_filter_available; | ||
| 36 | gboolean graph_follows; | 47 | gboolean graph_follows; |
| 48 | gboolean sync_task_filters; | ||
| 49 | gboolean sync_event_filters; | ||
| 50 | struct filter_task *list_task_filter; | ||
| 51 | struct filter_task *list_hide_tasks; | ||
| 37 | }; | 52 | }; |
| 38 | 53 | ||
| 39 | #define offset_of(type, field) (long)(&((type *)0)->field) | 54 | #define offset_of(type, field) (long)(&((type *)0)->field) |
diff --git a/parse-events.h b/parse-events.h index bb2fe83..32a8ff0 100644 --- a/parse-events.h +++ b/parse-events.h | |||
| @@ -347,11 +347,21 @@ struct pevent { | |||
| 347 | struct event_format *last_event; | 347 | struct event_format *last_event; |
| 348 | }; | 348 | }; |
| 349 | 349 | ||
| 350 | /* Can be overridden */ | ||
| 350 | void die(char *fmt, ...); | 351 | void die(char *fmt, ...); |
| 351 | void *malloc_or_die(unsigned int size); | 352 | void *malloc_or_die(unsigned int size); |
| 352 | void warning(char *fmt, ...); | 353 | void warning(char *fmt, ...); |
| 353 | void pr_stat(char *fmt, ...); | 354 | void pr_stat(char *fmt, ...); |
| 354 | 355 | ||
| 356 | /* Always available */ | ||
| 357 | void __die(char *fmt, ...); | ||
| 358 | void __warning(char *fmt, ...); | ||
| 359 | void __pr_stat(char *fmt, ...); | ||
| 360 | |||
| 361 | void __vdie(char *fmt, ...); | ||
| 362 | void __vwarning(char *fmt, ...); | ||
| 363 | void __vpr_stat(char *fmt, ...); | ||
| 364 | |||
| 355 | static inline unsigned short | 365 | static inline unsigned short |
| 356 | __data2host2(struct pevent *pevent, unsigned short data) | 366 | __data2host2(struct pevent *pevent, unsigned short data) |
| 357 | { | 367 | { |
| @@ -702,4 +712,6 @@ int pevent_filter_copy(struct event_filter *dest, struct event_filter *source); | |||
| 702 | int pevent_update_trivial(struct event_filter *dest, struct event_filter *source, | 712 | int pevent_update_trivial(struct event_filter *dest, struct event_filter *source, |
| 703 | enum filter_trivial_type type); | 713 | enum filter_trivial_type type); |
| 704 | 714 | ||
| 715 | int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2); | ||
| 716 | |||
| 705 | #endif /* _PARSE_EVENTS_H */ | 717 | #endif /* _PARSE_EVENTS_H */ |
diff --git a/parse-filter.c b/parse-filter.c index 4efce04..75512e3 100644 --- a/parse-filter.c +++ b/parse-filter.c | |||
| @@ -2026,3 +2026,60 @@ pevent_filter_make_string(struct event_filter *filter, int event_id) | |||
| 2026 | return arg_to_str(filter, filter_type->filter); | 2026 | return arg_to_str(filter, filter_type->filter); |
| 2027 | } | 2027 | } |
| 2028 | 2028 | ||
| 2029 | /** | ||
| 2030 | * pevent_filter_compare - compare two filters and return if they are the same | ||
| 2031 | * @filter1: Filter to compare with @filter2 | ||
| 2032 | * @filter2: Filter to compare with @filter1 | ||
| 2033 | * | ||
| 2034 | * Returns: | ||
| 2035 | * 1 if the two filters hold the same content. | ||
| 2036 | * 0 if they do not. | ||
| 2037 | */ | ||
| 2038 | int pevent_filter_compare(struct event_filter *filter1, struct event_filter *filter2) | ||
| 2039 | { | ||
| 2040 | struct filter_type *filter_type1; | ||
| 2041 | struct filter_type *filter_type2; | ||
| 2042 | char *str1, *str2; | ||
| 2043 | int result; | ||
| 2044 | int i; | ||
| 2045 | |||
| 2046 | /* Do the easy checks first */ | ||
| 2047 | if (filter1->filters != filter2->filters) | ||
| 2048 | return 0; | ||
| 2049 | if (!filter1->filters && !filter2->filters) | ||
| 2050 | return 1; | ||
| 2051 | |||
| 2052 | /* | ||
| 2053 | * Now take a look at each of the events to see if they have the same | ||
| 2054 | * filters to them. | ||
| 2055 | */ | ||
| 2056 | for (i = 0; i < filter1->filters; i++) { | ||
| 2057 | filter_type1 = &filter1->event_filters[i]; | ||
| 2058 | filter_type2 = find_filter_type(filter2, filter_type1->event_id); | ||
| 2059 | if (!filter_type2) | ||
| 2060 | break; | ||
| 2061 | if (filter_type1->filter->type != filter_type2->filter->type) | ||
| 2062 | break; | ||
| 2063 | switch (filter_type1->filter->type) { | ||
| 2064 | case FILTER_TRIVIAL_FALSE: | ||
| 2065 | case FILTER_TRIVIAL_TRUE: | ||
| 2066 | /* trivial types just need the type compared */ | ||
| 2067 | continue; | ||
| 2068 | default: | ||
| 2069 | break; | ||
| 2070 | } | ||
| 2071 | /* The best way to compare complex filters is with strings */ | ||
| 2072 | str1 = arg_to_str(filter1, filter_type1->filter); | ||
| 2073 | str2 = arg_to_str(filter2, filter_type2->filter); | ||
| 2074 | result = strcmp(str1, str2) != 0; | ||
| 2075 | free(str1); | ||
| 2076 | free(str2); | ||
| 2077 | if (result) | ||
| 2078 | break; | ||
| 2079 | } | ||
| 2080 | |||
| 2081 | if (i < filter1->filters) | ||
| 2082 | return 0; | ||
| 2083 | return 1; | ||
| 2084 | } | ||
| 2085 | |||
diff --git a/parse-utils.c b/parse-utils.c new file mode 100644 index 0000000..103bbd8 --- /dev/null +++ b/parse-utils.c | |||
| @@ -0,0 +1,105 @@ | |||
| 1 | #include <stdio.h> | ||
| 2 | #include <stdlib.h> | ||
| 3 | #include <string.h> | ||
| 4 | #include <stdarg.h> | ||
| 5 | #include <errno.h> | ||
| 6 | |||
| 7 | #define __weak __attribute__((weak)) | ||
| 8 | |||
| 9 | void __vdie(char *fmt, va_list ap) | ||
| 10 | { | ||
| 11 | int ret = errno; | ||
| 12 | |||
| 13 | if (errno) | ||
| 14 | perror("trace-cmd"); | ||
| 15 | else | ||
| 16 | ret = -1; | ||
| 17 | |||
| 18 | fprintf(stderr, " "); | ||
| 19 | vfprintf(stderr, fmt, ap); | ||
| 20 | |||
| 21 | fprintf(stderr, "\n"); | ||
| 22 | exit(ret); | ||
| 23 | } | ||
| 24 | |||
| 25 | void __die(char *fmt, ...) | ||
| 26 | { | ||
| 27 | va_list ap; | ||
| 28 | |||
| 29 | va_start(ap, fmt); | ||
| 30 | __vdie(fmt, ap); | ||
| 31 | va_end(ap); | ||
| 32 | } | ||
| 33 | |||
| 34 | void __weak die(char *fmt, ...) | ||
| 35 | { | ||
| 36 | va_list ap; | ||
| 37 | |||
| 38 | va_start(ap, fmt); | ||
| 39 | __vdie(fmt, ap); | ||
| 40 | va_end(ap); | ||
| 41 | } | ||
| 42 | |||
| 43 | void __vwarning(char *fmt, va_list ap) | ||
| 44 | { | ||
| 45 | if (errno) | ||
| 46 | perror("trace-cmd"); | ||
| 47 | errno = 0; | ||
| 48 | |||
| 49 | fprintf(stderr, " "); | ||
| 50 | vfprintf(stderr, fmt, ap); | ||
| 51 | |||
| 52 | fprintf(stderr, "\n"); | ||
| 53 | } | ||
| 54 | |||
| 55 | void __warning(char *fmt, ...) | ||
| 56 | { | ||
| 57 | va_list ap; | ||
| 58 | |||
| 59 | va_start(ap, fmt); | ||
| 60 | __vwarning(fmt, ap); | ||
| 61 | va_end(ap); | ||
| 62 | } | ||
| 63 | |||
| 64 | void __weak warning(char *fmt, ...) | ||
| 65 | { | ||
| 66 | va_list ap; | ||
| 67 | |||
| 68 | va_start(ap, fmt); | ||
| 69 | __vwarning(fmt, ap); | ||
| 70 | va_end(ap); | ||
| 71 | } | ||
| 72 | |||
| 73 | void __vpr_stat(char *fmt, va_list ap) | ||
| 74 | { | ||
| 75 | vprintf(fmt, ap); | ||
| 76 | printf("\n"); | ||
| 77 | } | ||
| 78 | |||
| 79 | void __pr_stat(char *fmt, ...) | ||
| 80 | { | ||
| 81 | va_list ap; | ||
| 82 | |||
| 83 | va_start(ap, fmt); | ||
| 84 | __vpr_stat(fmt, ap); | ||
| 85 | va_end(ap); | ||
| 86 | } | ||
| 87 | |||
| 88 | void __weak pr_stat(char *fmt, ...) | ||
| 89 | { | ||
| 90 | va_list ap; | ||
| 91 | |||
| 92 | va_start(ap, fmt); | ||
| 93 | __vpr_stat(fmt, ap); | ||
| 94 | va_end(ap); | ||
| 95 | } | ||
| 96 | |||
| 97 | void __weak *malloc_or_die(unsigned int size) | ||
| 98 | { | ||
| 99 | void *data; | ||
| 100 | |||
| 101 | data = malloc(size); | ||
| 102 | if (!data) | ||
| 103 | die("malloc"); | ||
| 104 | return data; | ||
| 105 | } | ||
diff --git a/trace-compat.c b/trace-compat.c index 5082757..e1652e0 100644 --- a/trace-compat.c +++ b/trace-compat.c | |||
| @@ -22,6 +22,10 @@ | |||
| 22 | * Linux Kernel that were written by Frederic Weisbecker. | 22 | * Linux Kernel that were written by Frederic Weisbecker. |
| 23 | */ | 23 | */ |
| 24 | #include "trace-compat.h" | 24 | #include "trace-compat.h" |
| 25 | #include "trace-gui.h" | ||
| 26 | #include "trace-cmd.h" | ||
| 27 | |||
| 28 | #include <gdk/gdk.h> | ||
| 25 | 29 | ||
| 26 | #if GTK_VERSION < CALC_GTK_VERSION(2,18,0) | 30 | #if GTK_VERSION < CALC_GTK_VERSION(2,18,0) |
| 27 | 31 | ||
| @@ -70,6 +74,24 @@ gdouble gtk_adjustment_get_lower(GtkAdjustment *adj) | |||
| 70 | return adj->lower; | 74 | return adj->lower; |
| 71 | } | 75 | } |
| 72 | 76 | ||
| 77 | gboolean gtk_show_uri(GdkScreen *screen, const gchar *uri, | ||
| 78 | guint32 timestamp, GError **error) | ||
| 79 | { | ||
| 80 | return FALSE; | ||
| 81 | } | ||
| 82 | |||
| 83 | void g_string_vprintf(GString *string, const gchar *format, va_list args) | ||
| 84 | { | ||
| 85 | char buf[1024]; | ||
| 86 | gint len; | ||
| 87 | |||
| 88 | len = vsnprintf(buf, 1024, format, args); | ||
| 89 | if (len >= 1024) | ||
| 90 | die("compat g_string_vprintf can not process length of %d\n", len); | ||
| 91 | |||
| 92 | g_string_printf(string, "%s", buf); | ||
| 93 | } | ||
| 94 | |||
| 73 | #endif /* version < 2.14.0 */ | 95 | #endif /* version < 2.14.0 */ |
| 74 | 96 | ||
| 75 | #if GTK_VERSION < CALC_GTK_VERSION(2,12,0) | 97 | #if GTK_VERSION < CALC_GTK_VERSION(2,12,0) |
| @@ -79,4 +101,20 @@ GtkWidget *gtk_tree_view_column_get_tree_view(GtkTreeViewColumn *col) | |||
| 79 | return col->tree_view; | 101 | return col->tree_view; |
| 80 | } | 102 | } |
| 81 | 103 | ||
| 104 | void gtk_widget_set_tooltip_text(GtkWidget *widget, const gchar *text) | ||
| 105 | { | ||
| 106 | static GtkTooltips *tooltips; | ||
| 107 | |||
| 108 | /* Only works for widgets with windows, sorry */ | ||
| 109 | if (GTK_WIDGET_NO_WINDOW(widget)) | ||
| 110 | return; | ||
| 111 | |||
| 112 | if (!tooltips) { | ||
| 113 | tooltips = gtk_tooltips_new(); | ||
| 114 | gtk_tooltips_enable(tooltips); | ||
| 115 | } | ||
| 116 | |||
| 117 | gtk_tooltips_set_tip(GTK_TOOLTIPS(tooltips), widget, text, text); | ||
| 118 | } | ||
| 119 | |||
| 82 | #endif /* version < 2.12.0 */ | 120 | #endif /* version < 2.12.0 */ |
diff --git a/trace-compat.h b/trace-compat.h index 1c9126d..ce7759d 100644 --- a/trace-compat.h +++ b/trace-compat.h | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #define _TRACE_COMPAT_H | 22 | #define _TRACE_COMPAT_H |
| 23 | 23 | ||
| 24 | #include <gtk/gtk.h> | 24 | #include <gtk/gtk.h> |
| 25 | #include <stdarg.h> | ||
| 25 | 26 | ||
| 26 | #define CALC_GTK_VERSION(maj, min, ext) ((maj << 16) + (min << 8) + ext) | 27 | #define CALC_GTK_VERSION(maj, min, ext) ((maj << 16) + (min << 8) + ext) |
| 27 | 28 | ||
| @@ -43,12 +44,17 @@ void gtk_menu_item_set_label(GtkMenuItem *menu_item, const gchar *label); | |||
| 43 | gdouble gtk_adjustment_get_page_size(GtkAdjustment *adj); | 44 | gdouble gtk_adjustment_get_page_size(GtkAdjustment *adj); |
| 44 | gdouble gtk_adjustment_get_upper(GtkAdjustment *adj); | 45 | gdouble gtk_adjustment_get_upper(GtkAdjustment *adj); |
| 45 | gdouble gtk_adjustment_get_lower(GtkAdjustment *adj); | 46 | gdouble gtk_adjustment_get_lower(GtkAdjustment *adj); |
| 47 | gboolean gtk_show_uri(GdkScreen *screen, const gchar *uri, | ||
| 48 | guint32 timestamp, GError **error); | ||
| 49 | |||
| 50 | void g_string_vprintf(GString *string, const gchar *format, va_list args); | ||
| 46 | 51 | ||
| 47 | #endif /* version < 2.14.0 */ | 52 | #endif /* version < 2.14.0 */ |
| 48 | 53 | ||
| 49 | #if GTK_VERSION < CALC_GTK_VERSION(2,12,0) | 54 | #if GTK_VERSION < CALC_GTK_VERSION(2,12,0) |
| 50 | 55 | ||
| 51 | GtkWidget *gtk_tree_view_column_get_tree_view(GtkTreeViewColumn *col); | 56 | GtkWidget *gtk_tree_view_column_get_tree_view(GtkTreeViewColumn *col); |
| 57 | void gtk_widget_set_tooltip_text(GtkWidget *widget, const gchar *text); | ||
| 52 | 58 | ||
| 53 | #endif /* version < 2.12.0 */ | 59 | #endif /* version < 2.12.0 */ |
| 54 | 60 | ||
diff --git a/trace-dialog.c b/trace-dialog.c new file mode 100644 index 0000000..c220a52 --- /dev/null +++ b/trace-dialog.c | |||
| @@ -0,0 +1,277 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; version 2 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | * | ||
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 20 | */ | ||
| 21 | #include <gtk/gtk.h> | ||
| 22 | #include <stdlib.h> | ||
| 23 | #include <string.h> | ||
| 24 | #include <stdarg.h> | ||
| 25 | #include <errno.h> | ||
| 26 | #include <ctype.h> | ||
| 27 | |||
| 28 | #include "trace-compat.h" | ||
| 29 | #include "trace-cmd.h" | ||
| 30 | #include "trace-gui.h" | ||
| 31 | |||
| 32 | #define DIALOG_WIDTH 500 | ||
| 33 | #define DIALOG_HEIGHT 550 | ||
| 34 | |||
| 35 | static GtkWidget *statusbar; | ||
| 36 | static GtkWidget *statuspix; | ||
| 37 | static GString *statusstr; | ||
| 38 | |||
| 39 | static GtkWidget *parent_window; | ||
| 40 | |||
| 41 | void pr_stat(char *fmt, ...) | ||
| 42 | { | ||
| 43 | GString *str; | ||
| 44 | va_list ap; | ||
| 45 | |||
| 46 | if (!statusstr) { | ||
| 47 | statusstr = g_string_new(""); | ||
| 48 | if (!statusstr) | ||
| 49 | die("Allocating status string"); | ||
| 50 | } | ||
| 51 | |||
| 52 | str = g_string_new(""); | ||
| 53 | |||
| 54 | va_start(ap, fmt); | ||
| 55 | g_string_vprintf(str, fmt, ap); | ||
| 56 | va_end(ap); | ||
| 57 | |||
| 58 | g_string_append_printf(statusstr, "%s\n", str->str); | ||
| 59 | |||
| 60 | if (statusbar) { | ||
| 61 | gtk_statusbar_push(GTK_STATUSBAR(statusbar), 1, str->str); | ||
| 62 | gtk_widget_show(statuspix); | ||
| 63 | } | ||
| 64 | |||
| 65 | g_string_free(str, TRUE); | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * trace_dialog_register_window - register window for warning dialogs | ||
| 70 | * @window: parent window to use for other dialogs | ||
| 71 | * | ||
| 72 | * The warning messages do not have a way to pass the window to | ||
| 73 | * the function, since these functions are also used by the command | ||
| 74 | * line interface. This allows an application to give the warning | ||
| 75 | * messages a window to use. | ||
| 76 | */ | ||
| 77 | void trace_dialog_register_window(GtkWidget *window) | ||
| 78 | { | ||
| 79 | parent_window = window; | ||
| 80 | } | ||
| 81 | |||
| 82 | void warning(char *fmt, ...) | ||
| 83 | { | ||
| 84 | GString *str; | ||
| 85 | va_list ap; | ||
| 86 | |||
| 87 | if (!parent_window) { | ||
| 88 | va_start(ap, fmt); | ||
| 89 | __vwarning(fmt, ap); | ||
| 90 | va_end(ap); | ||
| 91 | return; | ||
| 92 | } | ||
| 93 | |||
| 94 | str = g_string_new(""); | ||
| 95 | |||
| 96 | va_start(ap, fmt); | ||
| 97 | g_string_vprintf(str, fmt, ap); | ||
| 98 | va_end(ap); | ||
| 99 | |||
| 100 | g_string_append(str, "\n"); | ||
| 101 | |||
| 102 | if (errno) | ||
| 103 | g_string_prepend(str, strerror(errno)); | ||
| 104 | |||
| 105 | errno = 0; | ||
| 106 | |||
| 107 | trace_dialog(GTK_WINDOW(parent_window), TRACE_GUI_WARNING, | ||
| 108 | str->str); | ||
| 109 | |||
| 110 | g_string_free(str, TRUE); | ||
| 111 | } | ||
| 112 | |||
| 113 | static void | ||
| 114 | status_display_clicked (gpointer data) | ||
| 115 | { | ||
| 116 | GtkWidget *dialog; | ||
| 117 | GtkWidget *scrollwin; | ||
| 118 | GtkWidget *viewport; | ||
| 119 | GtkWidget *textview; | ||
| 120 | GtkTextBuffer *buffer; | ||
| 121 | |||
| 122 | dialog = gtk_dialog_new_with_buttons("Status", | ||
| 123 | NULL, | ||
| 124 | GTK_DIALOG_MODAL, | ||
| 125 | "OK", | ||
| 126 | GTK_RESPONSE_ACCEPT, | ||
| 127 | NULL); | ||
| 128 | |||
| 129 | scrollwin = gtk_scrolled_window_new(NULL, NULL); | ||
| 130 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | ||
| 131 | GTK_POLICY_AUTOMATIC, | ||
| 132 | GTK_POLICY_AUTOMATIC); | ||
| 133 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0); | ||
| 134 | gtk_widget_show(scrollwin); | ||
| 135 | |||
| 136 | viewport = gtk_viewport_new(NULL, NULL); | ||
| 137 | gtk_widget_show(viewport); | ||
| 138 | |||
| 139 | gtk_container_add(GTK_CONTAINER(scrollwin), viewport); | ||
| 140 | |||
| 141 | textview = gtk_text_view_new(); | ||
| 142 | buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); | ||
| 143 | gtk_text_buffer_set_text(buffer, statusstr->str, -1); | ||
| 144 | |||
| 145 | gtk_container_add(GTK_CONTAINER(viewport), textview); | ||
| 146 | gtk_widget_show(textview); | ||
| 147 | |||
| 148 | gtk_widget_set_size_request(GTK_WIDGET(dialog), | ||
| 149 | DIALOG_WIDTH, DIALOG_HEIGHT); | ||
| 150 | |||
| 151 | gtk_dialog_run(GTK_DIALOG(dialog)); | ||
| 152 | |||
| 153 | gtk_widget_destroy(dialog); | ||
| 154 | } | ||
| 155 | |||
| 156 | static gboolean | ||
| 157 | do_status_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | ||
| 158 | { | ||
| 159 | static GtkWidget *menu; | ||
| 160 | static GtkWidget *menu_status_display; | ||
| 161 | |||
| 162 | if (!menu) { | ||
| 163 | menu = gtk_menu_new(); | ||
| 164 | menu_status_display = gtk_menu_item_new_with_label("Display Status"); | ||
| 165 | gtk_widget_show(menu_status_display); | ||
| 166 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_status_display); | ||
| 167 | |||
| 168 | g_signal_connect_swapped (G_OBJECT (menu_status_display), "activate", | ||
| 169 | G_CALLBACK (status_display_clicked), | ||
| 170 | data); | ||
| 171 | } | ||
| 172 | |||
| 173 | gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, | ||
| 174 | gtk_get_current_event_time()); | ||
| 175 | |||
| 176 | return TRUE; | ||
| 177 | } | ||
| 178 | |||
| 179 | static gboolean | ||
| 180 | button_press_status(GtkWidget *widget, GdkEventButton *event, gpointer data) | ||
| 181 | { | ||
| 182 | if (event->button == 1) | ||
| 183 | return do_status_popup(widget, event, data); | ||
| 184 | |||
| 185 | return FALSE; | ||
| 186 | } | ||
| 187 | |||
| 188 | GtkWidget *trace_status_bar_new(void) | ||
| 189 | { | ||
| 190 | GtkWidget *eventbox; | ||
| 191 | |||
| 192 | statusbar = gtk_statusbar_new(); | ||
| 193 | |||
| 194 | statuspix = gtk_image_new_from_stock(GTK_STOCK_INFO, | ||
| 195 | GTK_ICON_SIZE_SMALL_TOOLBAR); | ||
| 196 | |||
| 197 | eventbox = gtk_event_box_new(); | ||
| 198 | gtk_container_add(GTK_CONTAINER(eventbox), statuspix); | ||
| 199 | gtk_widget_show(eventbox); | ||
| 200 | |||
| 201 | gtk_box_pack_end(GTK_BOX(statusbar), eventbox, FALSE, FALSE, 0); | ||
| 202 | |||
| 203 | if (statusstr) | ||
| 204 | gtk_widget_show(statuspix); | ||
| 205 | |||
| 206 | gtk_signal_connect(GTK_OBJECT(eventbox), "button_press_event", | ||
| 207 | (GtkSignalFunc) button_press_status, NULL); | ||
| 208 | |||
| 209 | return statusbar; | ||
| 210 | } | ||
| 211 | |||
| 212 | void trace_show_help(GtkWidget *window, const gchar *link, GError **error) | ||
| 213 | { | ||
| 214 | #if GTK_VERSION < CALC_GTK_VERSION(2,14,0) | ||
| 215 | trace_dialog(GTK_WINDOW(window), TRACE_GUI_WARNING, | ||
| 216 | "This version of GTK+ does not implement gtk_show_uri.\n" | ||
| 217 | "Please upgrade your GTK and recompile"); | ||
| 218 | #else | ||
| 219 | gtk_show_uri(gtk_widget_get_screen(GTK_WIDGET(window)), | ||
| 220 | link, | ||
| 221 | GDK_CURRENT_TIME, | ||
| 222 | error); | ||
| 223 | #endif | ||
| 224 | } | ||
| 225 | |||
| 226 | void trace_dialog(GtkWindow *parent, enum trace_dialog_type type, | ||
| 227 | gchar *message, ...) | ||
| 228 | { | ||
| 229 | GtkWidget *dialog; | ||
| 230 | GtkMessageType mtype; | ||
| 231 | gchar *str; | ||
| 232 | va_list ap; | ||
| 233 | |||
| 234 | switch (type) { | ||
| 235 | case TRACE_GUI_INFO: | ||
| 236 | mtype = GTK_MESSAGE_INFO; | ||
| 237 | break; | ||
| 238 | case TRACE_GUI_WARNING: | ||
| 239 | mtype = GTK_MESSAGE_WARNING; | ||
| 240 | break; | ||
| 241 | case TRACE_GUI_ERROR: | ||
| 242 | mtype = GTK_MESSAGE_ERROR; | ||
| 243 | break; | ||
| 244 | } | ||
| 245 | |||
| 246 | va_start(ap, message); | ||
| 247 | str = g_strdup_vprintf(message, ap); | ||
| 248 | va_end(ap); | ||
| 249 | |||
| 250 | dialog = gtk_message_dialog_new(parent, | ||
| 251 | GTK_DIALOG_DESTROY_WITH_PARENT, | ||
| 252 | mtype, | ||
| 253 | GTK_BUTTONS_CLOSE, | ||
| 254 | "%s", str); | ||
| 255 | g_free(str); | ||
| 256 | gtk_dialog_run(GTK_DIALOG(dialog)); | ||
| 257 | gtk_widget_destroy(dialog); | ||
| 258 | } | ||
| 259 | |||
| 260 | gchar *trace_get_file_dialog(const gchar *title) | ||
| 261 | { | ||
| 262 | GtkWidget *dialog; | ||
| 263 | gchar *filename = NULL; | ||
| 264 | |||
| 265 | dialog = gtk_file_chooser_dialog_new(title, | ||
| 266 | NULL, | ||
| 267 | GTK_FILE_CHOOSER_ACTION_OPEN, | ||
| 268 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | ||
| 269 | GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, | ||
| 270 | NULL); | ||
| 271 | if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) | ||
| 272 | filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); | ||
| 273 | |||
| 274 | gtk_widget_destroy(dialog); | ||
| 275 | |||
| 276 | return filename; | ||
| 277 | } | ||
diff --git a/trace-filter.c b/trace-filter.c index 15d59c0..b8fc76f 100644 --- a/trace-filter.c +++ b/trace-filter.c | |||
| @@ -58,11 +58,6 @@ int id_cmp(const void *a, const void *b) | |||
| 58 | return 0; | 58 | return 0; |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | struct dialog_helper { | ||
| 62 | GtkWidget *dialog; | ||
| 63 | gpointer data; | ||
| 64 | }; | ||
| 65 | |||
| 66 | /** | 61 | /** |
| 67 | * trace_array_add - allocate and add an int to an array. | 62 | * trace_array_add - allocate and add an int to an array. |
| 68 | * @array: address of array to allocate | 63 | * @array: address of array to allocate |
| @@ -97,14 +92,7 @@ struct event_combo_info { | |||
| 97 | GtkWidget *event_combo; | 92 | GtkWidget *event_combo; |
| 98 | GtkWidget *op_combo; | 93 | GtkWidget *op_combo; |
| 99 | GtkWidget *field_combo; | 94 | GtkWidget *field_combo; |
| 100 | }; | 95 | GtkWidget *entry; |
| 101 | |||
| 102 | struct adv_event_filter_helper { | ||
| 103 | trace_adv_filter_cb_func func; | ||
| 104 | GtkTreeView *view; | ||
| 105 | GtkWidget *entry; | ||
| 106 | struct event_combo_info combo_info; | ||
| 107 | gpointer data; | ||
| 108 | }; | 96 | }; |
| 109 | 97 | ||
| 110 | static GtkTreeModel *create_event_combo_model(struct pevent *pevent) | 98 | static GtkTreeModel *create_event_combo_model(struct pevent *pevent) |
| @@ -319,7 +307,6 @@ static void event_combo_changed(GtkComboBox *combo, gpointer data) | |||
| 319 | static void insert_combo_text(struct event_combo_info *info, | 307 | static void insert_combo_text(struct event_combo_info *info, |
| 320 | GtkComboBox *combo) | 308 | GtkComboBox *combo) |
| 321 | { | 309 | { |
| 322 | struct adv_event_filter_helper *event_helper; | ||
| 323 | GtkTreeModel *model; | 310 | GtkTreeModel *model; |
| 324 | GtkTreeIter iter; | 311 | GtkTreeIter iter; |
| 325 | GtkWidget *entry; | 312 | GtkWidget *entry; |
| @@ -337,8 +324,7 @@ static void insert_combo_text(struct event_combo_info *info, | |||
| 337 | 0, &text, | 324 | 0, &text, |
| 338 | -1); | 325 | -1); |
| 339 | 326 | ||
| 340 | event_helper = container_of(info, typeof(*event_helper), combo_info); | 327 | entry = info->entry; |
| 341 | entry = event_helper->entry; | ||
| 342 | 328 | ||
| 343 | pos = gtk_editable_get_position(GTK_EDITABLE(entry)); | 329 | pos = gtk_editable_get_position(GTK_EDITABLE(entry)); |
| 344 | gtk_editable_insert_text(GTK_EDITABLE(entry), text, strlen(text), &pos); | 330 | gtk_editable_insert_text(GTK_EDITABLE(entry), text, strlen(text), &pos); |
| @@ -506,35 +492,6 @@ static gint *get_event_ids(GtkTreeView *treeview) | |||
| 506 | return ids; | 492 | return ids; |
| 507 | } | 493 | } |
| 508 | 494 | ||
| 509 | /* Callback for the clicked signal of the advanced filter button */ | ||
| 510 | static void | ||
| 511 | adv_filter_dialog_response (gpointer data, gint response_id) | ||
| 512 | { | ||
| 513 | struct dialog_helper *helper = data; | ||
| 514 | struct adv_event_filter_helper *event_helper = helper->data; | ||
| 515 | const gchar *text; | ||
| 516 | gint *event_ids; | ||
| 517 | |||
| 518 | switch (response_id) { | ||
| 519 | case GTK_RESPONSE_ACCEPT: | ||
| 520 | text = gtk_entry_get_text(GTK_ENTRY(event_helper->entry)); | ||
| 521 | event_ids = get_event_ids(event_helper->view); | ||
| 522 | event_helper->func(TRUE, text, event_ids, event_helper->data); | ||
| 523 | free(event_ids); | ||
| 524 | break; | ||
| 525 | case GTK_RESPONSE_REJECT: | ||
| 526 | event_helper->func(FALSE, NULL, NULL, event_helper->data); | ||
| 527 | break; | ||
| 528 | default: | ||
| 529 | break; | ||
| 530 | }; | ||
| 531 | |||
| 532 | gtk_widget_destroy(GTK_WIDGET(helper->dialog)); | ||
| 533 | |||
| 534 | g_free(event_helper); | ||
| 535 | g_free(helper); | ||
| 536 | } | ||
| 537 | |||
| 538 | static GtkTreeModel * | 495 | static GtkTreeModel * |
| 539 | create_tree_filter_model(struct tracecmd_input *handle, | 496 | create_tree_filter_model(struct tracecmd_input *handle, |
| 540 | struct event_filter *event_filter) | 497 | struct event_filter *event_filter) |
| @@ -706,9 +663,8 @@ void trace_adv_filter_dialog(struct tracecmd_input *handle, | |||
| 706 | trace_adv_filter_cb_func func, | 663 | trace_adv_filter_cb_func func, |
| 707 | gpointer data) | 664 | gpointer data) |
| 708 | { | 665 | { |
| 666 | struct event_combo_info combo_info; | ||
| 709 | struct pevent *pevent; | 667 | struct pevent *pevent; |
| 710 | struct dialog_helper *helper; | ||
| 711 | struct adv_event_filter_helper *event_helper; | ||
| 712 | GtkWidget *dialog; | 668 | GtkWidget *dialog; |
| 713 | GtkWidget *hbox; | 669 | GtkWidget *hbox; |
| 714 | GtkWidget *label; | 670 | GtkWidget *label; |
| @@ -716,13 +672,13 @@ void trace_adv_filter_dialog(struct tracecmd_input *handle, | |||
| 716 | GtkWidget *scrollwin; | 672 | GtkWidget *scrollwin; |
| 717 | GtkWidget *view; | 673 | GtkWidget *view; |
| 718 | GtkWidget *event_box; | 674 | GtkWidget *event_box; |
| 675 | const gchar *text; | ||
| 676 | gint *event_ids; | ||
| 677 | int result; | ||
| 719 | 678 | ||
| 720 | if (!handle) | 679 | if (!handle) |
| 721 | return; | 680 | return; |
| 722 | 681 | ||
| 723 | helper = g_malloc(sizeof(*helper)); | ||
| 724 | g_assert(helper); | ||
| 725 | |||
| 726 | /* --- Make dialog window --- */ | 682 | /* --- Make dialog window --- */ |
| 727 | 683 | ||
| 728 | dialog = gtk_dialog_new_with_buttons("Advanced Filters", | 684 | dialog = gtk_dialog_new_with_buttons("Advanced Filters", |
| @@ -734,26 +690,11 @@ void trace_adv_filter_dialog(struct tracecmd_input *handle, | |||
| 734 | GTK_RESPONSE_REJECT, | 690 | GTK_RESPONSE_REJECT, |
| 735 | NULL); | 691 | NULL); |
| 736 | 692 | ||
| 737 | event_helper = g_new0(typeof(*event_helper), 1); | ||
| 738 | g_assert(event_helper); | ||
| 739 | |||
| 740 | helper->dialog = dialog; | ||
| 741 | helper->data = event_helper; | ||
| 742 | |||
| 743 | event_helper->func = func; | ||
| 744 | event_helper->data = data; | ||
| 745 | |||
| 746 | /* We can attach the Quit menu item to our exit function */ | ||
| 747 | g_signal_connect_swapped (dialog, "response", | ||
| 748 | G_CALLBACK (adv_filter_dialog_response), | ||
| 749 | (gpointer) helper); | ||
| 750 | |||
| 751 | scrollwin = gtk_scrolled_window_new(NULL, NULL); | 693 | scrollwin = gtk_scrolled_window_new(NULL, NULL); |
| 752 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | 694 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), |
| 753 | GTK_POLICY_AUTOMATIC, | 695 | GTK_POLICY_AUTOMATIC, |
| 754 | GTK_POLICY_AUTOMATIC); | 696 | GTK_POLICY_AUTOMATIC); |
| 755 | view = create_adv_filter_view(handle, event_filter); | 697 | view = create_adv_filter_view(handle, event_filter); |
| 756 | event_helper->view = GTK_TREE_VIEW(view); | ||
| 757 | gtk_container_add(GTK_CONTAINER(scrollwin), view); | 698 | gtk_container_add(GTK_CONTAINER(scrollwin), view); |
| 758 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0); | 699 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0); |
| 759 | 700 | ||
| @@ -769,9 +710,9 @@ void trace_adv_filter_dialog(struct tracecmd_input *handle, | |||
| 769 | 710 | ||
| 770 | pevent = tracecmd_get_pevent(handle); | 711 | pevent = tracecmd_get_pevent(handle); |
| 771 | 712 | ||
| 772 | event_helper->combo_info.pevent = pevent; | 713 | combo_info.pevent = pevent; |
| 773 | 714 | ||
| 774 | event_box = event_info_box(&event_helper->combo_info); | 715 | event_box = event_info_box(&combo_info); |
| 775 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), event_box, FALSE, FALSE, 0); | 716 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), event_box, FALSE, FALSE, 0); |
| 776 | gtk_widget_show(event_box); | 717 | gtk_widget_show(event_box); |
| 777 | 718 | ||
| @@ -787,23 +728,33 @@ void trace_adv_filter_dialog(struct tracecmd_input *handle, | |||
| 787 | gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); | 728 | gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0); |
| 788 | gtk_widget_show(entry); | 729 | gtk_widget_show(entry); |
| 789 | 730 | ||
| 790 | event_helper->entry = entry; | 731 | combo_info.entry = entry; |
| 791 | 732 | ||
| 792 | gtk_widget_set_size_request(GTK_WIDGET(dialog), | 733 | gtk_widget_set_size_request(GTK_WIDGET(dialog), |
| 793 | TEXT_DIALOG_WIDTH, TEXT_DIALOG_HEIGHT); | 734 | TEXT_DIALOG_WIDTH, TEXT_DIALOG_HEIGHT); |
| 794 | 735 | ||
| 795 | gtk_widget_show_all(dialog); | 736 | gtk_widget_show_all(dialog); |
| 737 | |||
| 738 | result = gtk_dialog_run(GTK_DIALOG(dialog)); | ||
| 739 | switch (result) { | ||
| 740 | case GTK_RESPONSE_ACCEPT: | ||
| 741 | text = gtk_entry_get_text(GTK_ENTRY(entry)); | ||
| 742 | event_ids = get_event_ids(GTK_TREE_VIEW(view)); | ||
| 743 | func(TRUE, text, event_ids, data); | ||
| 744 | free(event_ids); | ||
| 745 | break; | ||
| 746 | case GTK_RESPONSE_REJECT: | ||
| 747 | func(FALSE, NULL, NULL, data); | ||
| 748 | break; | ||
| 749 | default: | ||
| 750 | break; | ||
| 751 | }; | ||
| 752 | |||
| 753 | gtk_widget_destroy(dialog); | ||
| 796 | } | 754 | } |
| 797 | 755 | ||
| 798 | /* --- task list dialog --- */ | 756 | /* --- task list dialog --- */ |
| 799 | 757 | ||
| 800 | struct task_helper { | ||
| 801 | trace_task_cb_func func; | ||
| 802 | GtkTreeView *view; | ||
| 803 | gboolean start; | ||
| 804 | gpointer data; | ||
| 805 | }; | ||
| 806 | |||
| 807 | enum { | 758 | enum { |
| 808 | TASK_COL_SELECT, | 759 | TASK_COL_SELECT, |
| 809 | TASK_COL_PID, | 760 | TASK_COL_PID, |
| @@ -850,35 +801,6 @@ static void get_tasks(GtkTreeView *treeview, | |||
| 850 | *non_selected = non_pids; | 801 | *non_selected = non_pids; |
| 851 | } | 802 | } |
| 852 | 803 | ||
| 853 | /* Callback for the clicked signal of the task filter button */ | ||
| 854 | static void | ||
| 855 | task_dialog_response (gpointer data, gint response_id) | ||
| 856 | { | ||
| 857 | struct dialog_helper *helper = data; | ||
| 858 | struct task_helper *event_helper = helper->data; | ||
| 859 | gint *selected; | ||
| 860 | gint *non_select; | ||
| 861 | |||
| 862 | switch (response_id) { | ||
| 863 | case GTK_RESPONSE_ACCEPT: | ||
| 864 | get_tasks(event_helper->view, &selected, &non_select); | ||
| 865 | event_helper->func(TRUE, selected, non_select, event_helper->data); | ||
| 866 | free(selected); | ||
| 867 | free(non_select); | ||
| 868 | break; | ||
| 869 | case GTK_RESPONSE_REJECT: | ||
| 870 | event_helper->func(FALSE, NULL, NULL, event_helper->data); | ||
| 871 | break; | ||
| 872 | default: | ||
| 873 | break; | ||
| 874 | }; | ||
| 875 | |||
| 876 | gtk_widget_destroy(GTK_WIDGET(helper->dialog)); | ||
| 877 | |||
| 878 | g_free(event_helper); | ||
| 879 | g_free(helper); | ||
| 880 | } | ||
| 881 | |||
| 882 | static GtkTreeModel * | 804 | static GtkTreeModel * |
| 883 | create_task_model(struct tracecmd_input *handle, | 805 | create_task_model(struct tracecmd_input *handle, |
| 884 | gint *tasks, | 806 | gint *tasks, |
| @@ -960,14 +882,14 @@ create_task_model(struct tracecmd_input *handle, | |||
| 960 | 882 | ||
| 961 | static void task_cursor_changed(gpointer data, GtkTreeView *treeview) | 883 | static void task_cursor_changed(gpointer data, GtkTreeView *treeview) |
| 962 | { | 884 | { |
| 963 | struct task_helper *event_helper = data; | 885 | gboolean *start = data; |
| 964 | GtkTreeModel *model; | 886 | GtkTreeModel *model; |
| 965 | GtkTreePath *path; | 887 | GtkTreePath *path; |
| 966 | GtkTreeIter iter; | 888 | GtkTreeIter iter; |
| 967 | gboolean active; | 889 | gboolean active; |
| 968 | 890 | ||
| 969 | if (!event_helper->start) { | 891 | if (!*start) { |
| 970 | event_helper->start = TRUE; | 892 | *start = TRUE; |
| 971 | return; | 893 | return; |
| 972 | } | 894 | } |
| 973 | 895 | ||
| @@ -999,7 +921,7 @@ static void task_cursor_changed(gpointer data, GtkTreeView *treeview) | |||
| 999 | static GtkWidget * | 921 | static GtkWidget * |
| 1000 | create_task_view(struct tracecmd_input *handle, | 922 | create_task_view(struct tracecmd_input *handle, |
| 1001 | gint *tasks, gint *selected, | 923 | gint *tasks, gint *selected, |
| 1002 | struct task_helper *event_helper) | 924 | gboolean *start) |
| 1003 | { | 925 | { |
| 1004 | GtkTreeViewColumn *col; | 926 | GtkTreeViewColumn *col; |
| 1005 | GtkCellRenderer *renderer; | 927 | GtkCellRenderer *renderer; |
| @@ -1061,7 +983,7 @@ create_task_view(struct tracecmd_input *handle, | |||
| 1061 | 983 | ||
| 1062 | g_signal_connect_swapped (view, "cursor-changed", | 984 | g_signal_connect_swapped (view, "cursor-changed", |
| 1063 | G_CALLBACK (task_cursor_changed), | 985 | G_CALLBACK (task_cursor_changed), |
| 1064 | (gpointer) event_helper); | 986 | (gpointer)start); |
| 1065 | 987 | ||
| 1066 | return view; | 988 | return view; |
| 1067 | } | 989 | } |
| @@ -1080,14 +1002,12 @@ void trace_task_dialog(struct tracecmd_input *handle, | |||
| 1080 | trace_task_cb_func func, | 1002 | trace_task_cb_func func, |
| 1081 | gpointer data) | 1003 | gpointer data) |
| 1082 | { | 1004 | { |
| 1083 | struct dialog_helper *helper; | ||
| 1084 | struct task_helper *event_helper; | ||
| 1085 | GtkWidget *dialog; | 1005 | GtkWidget *dialog; |
| 1086 | GtkWidget *scrollwin; | 1006 | GtkWidget *scrollwin; |
| 1087 | GtkWidget *view; | 1007 | GtkWidget *view; |
| 1088 | 1008 | gboolean start = FALSE; | |
| 1089 | helper = g_malloc(sizeof(*helper)); | 1009 | gint *non_select; |
| 1090 | g_assert(helper); | 1010 | int result; |
| 1091 | 1011 | ||
| 1092 | /* --- Make dialog window --- */ | 1012 | /* --- Make dialog window --- */ |
| 1093 | 1013 | ||
| @@ -1100,27 +1020,11 @@ void trace_task_dialog(struct tracecmd_input *handle, | |||
| 1100 | GTK_RESPONSE_REJECT, | 1020 | GTK_RESPONSE_REJECT, |
| 1101 | NULL); | 1021 | NULL); |
| 1102 | 1022 | ||
| 1103 | event_helper = g_new0(typeof(*event_helper), 1); | ||
| 1104 | g_assert(event_helper); | ||
| 1105 | |||
| 1106 | helper->dialog = dialog; | ||
| 1107 | helper->data = event_helper; | ||
| 1108 | |||
| 1109 | event_helper->func = func; | ||
| 1110 | event_helper->data = data; | ||
| 1111 | event_helper->start = FALSE; | ||
| 1112 | |||
| 1113 | /* We can attach the Quit menu item to our exit function */ | ||
| 1114 | g_signal_connect_swapped (dialog, "response", | ||
| 1115 | G_CALLBACK (task_dialog_response), | ||
| 1116 | (gpointer) helper); | ||
| 1117 | |||
| 1118 | scrollwin = gtk_scrolled_window_new(NULL, NULL); | 1023 | scrollwin = gtk_scrolled_window_new(NULL, NULL); |
| 1119 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | 1024 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), |
| 1120 | GTK_POLICY_AUTOMATIC, | 1025 | GTK_POLICY_AUTOMATIC, |
| 1121 | GTK_POLICY_AUTOMATIC); | 1026 | GTK_POLICY_AUTOMATIC); |
| 1122 | view = create_task_view(handle, tasks, selected, event_helper); | 1027 | view = create_task_view(handle, tasks, selected, &start); |
| 1123 | event_helper->view = GTK_TREE_VIEW(view); | ||
| 1124 | gtk_container_add(GTK_CONTAINER(scrollwin), view); | 1028 | gtk_container_add(GTK_CONTAINER(scrollwin), view); |
| 1125 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0); | 1029 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0); |
| 1126 | 1030 | ||
| @@ -1128,6 +1032,25 @@ void trace_task_dialog(struct tracecmd_input *handle, | |||
| 1128 | DIALOG_WIDTH, DIALOG_HEIGHT); | 1032 | DIALOG_WIDTH, DIALOG_HEIGHT); |
| 1129 | 1033 | ||
| 1130 | gtk_widget_show_all(dialog); | 1034 | gtk_widget_show_all(dialog); |
| 1035 | |||
| 1036 | selected = NULL; | ||
| 1037 | |||
| 1038 | result = gtk_dialog_run(GTK_DIALOG(dialog)); | ||
| 1039 | switch (result) { | ||
| 1040 | case GTK_RESPONSE_ACCEPT: | ||
| 1041 | get_tasks(GTK_TREE_VIEW(view), &selected, &non_select); | ||
| 1042 | func(TRUE, selected, non_select, data); | ||
| 1043 | free(selected); | ||
| 1044 | free(non_select); | ||
| 1045 | break; | ||
| 1046 | case GTK_RESPONSE_REJECT: | ||
| 1047 | func(FALSE, NULL, NULL, data); | ||
| 1048 | break; | ||
| 1049 | default: | ||
| 1050 | break; | ||
| 1051 | }; | ||
| 1052 | |||
| 1053 | gtk_widget_destroy(dialog); | ||
| 1131 | } | 1054 | } |
| 1132 | 1055 | ||
| 1133 | enum { | 1056 | enum { |
| @@ -1602,9 +1525,9 @@ static gint update_system_events(GtkTreeModel *model, | |||
| 1602 | return size; | 1525 | return size; |
| 1603 | } | 1526 | } |
| 1604 | 1527 | ||
| 1605 | static void accept_events(struct event_filter_helper *event_helper) | 1528 | static void accept_events(GtkTreeView *view, |
| 1529 | trace_filter_event_cb_func func, gpointer data) | ||
| 1606 | { | 1530 | { |
| 1607 | GtkTreeView *view = event_helper->view; | ||
| 1608 | GtkTreeModel *model; | 1531 | GtkTreeModel *model; |
| 1609 | GtkTreeIter iter; | 1532 | GtkTreeIter iter; |
| 1610 | gboolean active; | 1533 | gboolean active; |
| @@ -1630,8 +1553,7 @@ static void accept_events(struct event_filter_helper *event_helper) | |||
| 1630 | &systems, systems_size, | 1553 | &systems, systems_size, |
| 1631 | &events, &events_size); | 1554 | &events, &events_size); |
| 1632 | 1555 | ||
| 1633 | event_helper->func(TRUE, active, systems, events, | 1556 | func(TRUE, active, systems, events, data); |
| 1634 | event_helper->data); | ||
| 1635 | 1557 | ||
| 1636 | if (systems) { | 1558 | if (systems) { |
| 1637 | for (i = 0; systems[i]; i++) | 1559 | for (i = 0; systems[i]; i++) |
| @@ -1642,33 +1564,6 @@ static void accept_events(struct event_filter_helper *event_helper) | |||
| 1642 | g_free(events); | 1564 | g_free(events); |
| 1643 | } | 1565 | } |
| 1644 | 1566 | ||
| 1645 | /* Callback for the clicked signal of the Events filter button */ | ||
| 1646 | static void | ||
| 1647 | event_dialog_response (gpointer data, gint response_id) | ||
| 1648 | { | ||
| 1649 | struct dialog_helper *helper = data; | ||
| 1650 | struct event_filter_helper *event_helper = helper->data; | ||
| 1651 | |||
| 1652 | switch (response_id) { | ||
| 1653 | case GTK_RESPONSE_ACCEPT: | ||
| 1654 | printf("accept!\n"); | ||
| 1655 | accept_events(event_helper); | ||
| 1656 | break; | ||
| 1657 | case GTK_RESPONSE_REJECT: | ||
| 1658 | printf("reject!\n"); | ||
| 1659 | event_helper->func(FALSE, FALSE, NULL, NULL, | ||
| 1660 | event_helper->data); | ||
| 1661 | break; | ||
| 1662 | default: | ||
| 1663 | break; | ||
| 1664 | }; | ||
| 1665 | |||
| 1666 | gtk_widget_destroy(GTK_WIDGET(helper->dialog)); | ||
| 1667 | |||
| 1668 | g_free(event_helper); | ||
| 1669 | g_free(helper); | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | static void filter_event_dialog(struct tracecmd_input *handle, | 1567 | static void filter_event_dialog(struct tracecmd_input *handle, |
| 1673 | struct event_filter *filter, | 1568 | struct event_filter *filter, |
| 1674 | gboolean all_events, | 1569 | gboolean all_events, |
| @@ -1676,13 +1571,10 @@ static void filter_event_dialog(struct tracecmd_input *handle, | |||
| 1676 | trace_filter_event_cb_func func, | 1571 | trace_filter_event_cb_func func, |
| 1677 | gpointer data) | 1572 | gpointer data) |
| 1678 | { | 1573 | { |
| 1679 | struct dialog_helper *helper; | ||
| 1680 | struct event_filter_helper *event_helper; | ||
| 1681 | GtkWidget *dialog; | 1574 | GtkWidget *dialog; |
| 1682 | GtkWidget *scrollwin; | 1575 | GtkWidget *scrollwin; |
| 1683 | GtkWidget *view; | 1576 | GtkWidget *view; |
| 1684 | 1577 | int result; | |
| 1685 | helper = g_malloc(sizeof(*helper)); | ||
| 1686 | 1578 | ||
| 1687 | /* --- Make dialog window --- */ | 1579 | /* --- Make dialog window --- */ |
| 1688 | 1580 | ||
| @@ -1695,26 +1587,11 @@ static void filter_event_dialog(struct tracecmd_input *handle, | |||
| 1695 | GTK_RESPONSE_REJECT, | 1587 | GTK_RESPONSE_REJECT, |
| 1696 | NULL); | 1588 | NULL); |
| 1697 | 1589 | ||
| 1698 | event_helper = g_new0(typeof(*event_helper), 1); | ||
| 1699 | g_assert(event_helper); | ||
| 1700 | |||
| 1701 | helper->dialog = dialog; | ||
| 1702 | helper->data = event_helper; | ||
| 1703 | |||
| 1704 | event_helper->func = func; | ||
| 1705 | event_helper->data = data; | ||
| 1706 | |||
| 1707 | /* We can attach the Quit menu item to our exit function */ | ||
| 1708 | g_signal_connect_swapped (dialog, "response", | ||
| 1709 | G_CALLBACK (event_dialog_response), | ||
| 1710 | (gpointer) helper); | ||
| 1711 | |||
| 1712 | scrollwin = gtk_scrolled_window_new(NULL, NULL); | 1590 | scrollwin = gtk_scrolled_window_new(NULL, NULL); |
| 1713 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | 1591 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), |
| 1714 | GTK_POLICY_AUTOMATIC, | 1592 | GTK_POLICY_AUTOMATIC, |
| 1715 | GTK_POLICY_AUTOMATIC); | 1593 | GTK_POLICY_AUTOMATIC); |
| 1716 | view = create_event_list_view(handle, filter, all_events, systems, events); | 1594 | view = create_event_list_view(handle, filter, all_events, systems, events); |
| 1717 | event_helper->view = GTK_TREE_VIEW(view); | ||
| 1718 | 1595 | ||
| 1719 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0); | 1596 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), scrollwin, TRUE, TRUE, 0); |
| 1720 | gtk_container_add(GTK_CONTAINER(scrollwin), view); | 1597 | gtk_container_add(GTK_CONTAINER(scrollwin), view); |
| @@ -1723,6 +1600,20 @@ static void filter_event_dialog(struct tracecmd_input *handle, | |||
| 1723 | DIALOG_WIDTH, DIALOG_HEIGHT); | 1600 | DIALOG_WIDTH, DIALOG_HEIGHT); |
| 1724 | 1601 | ||
| 1725 | gtk_widget_show_all(dialog); | 1602 | gtk_widget_show_all(dialog); |
| 1603 | |||
| 1604 | result = gtk_dialog_run(GTK_DIALOG(dialog)); | ||
| 1605 | switch (result) { | ||
| 1606 | case GTK_RESPONSE_ACCEPT: | ||
| 1607 | accept_events(GTK_TREE_VIEW(view), func, data); | ||
| 1608 | break; | ||
| 1609 | case GTK_RESPONSE_REJECT: | ||
| 1610 | func(FALSE, FALSE, NULL, NULL, data); | ||
| 1611 | break; | ||
| 1612 | default: | ||
| 1613 | break; | ||
| 1614 | }; | ||
| 1615 | |||
| 1616 | gtk_widget_destroy(dialog); | ||
| 1726 | } | 1617 | } |
| 1727 | 1618 | ||
| 1728 | /** | 1619 | /** |
| @@ -1779,8 +1670,6 @@ struct cpu_filter_helper { | |||
| 1779 | guint64 *cpu_mask; | 1670 | guint64 *cpu_mask; |
| 1780 | GtkWidget **buttons; | 1671 | GtkWidget **buttons; |
| 1781 | int cpus; | 1672 | int cpus; |
| 1782 | trace_filter_cpu_cb_func func; | ||
| 1783 | gpointer data; | ||
| 1784 | }; | 1673 | }; |
| 1785 | 1674 | ||
| 1786 | static void destroy_cpu_helper(struct cpu_filter_helper *cpu_helper) | 1675 | static void destroy_cpu_helper(struct cpu_filter_helper *cpu_helper) |
| @@ -1790,40 +1679,6 @@ static void destroy_cpu_helper(struct cpu_filter_helper *cpu_helper) | |||
| 1790 | g_free(cpu_helper); | 1679 | g_free(cpu_helper); |
| 1791 | } | 1680 | } |
| 1792 | 1681 | ||
| 1793 | /* Callback for the clicked signal of the CPUS filter button */ | ||
| 1794 | static void | ||
| 1795 | cpu_dialog_response (gpointer data, gint response_id) | ||
| 1796 | { | ||
| 1797 | struct dialog_helper *helper = data; | ||
| 1798 | struct cpu_filter_helper *cpu_helper = helper->data; | ||
| 1799 | guint64 *cpu_mask = NULL; | ||
| 1800 | |||
| 1801 | switch (response_id) { | ||
| 1802 | case GTK_RESPONSE_ACCEPT: | ||
| 1803 | |||
| 1804 | if (!cpu_helper->allcpus) { | ||
| 1805 | cpu_mask = cpu_helper->cpu_mask; | ||
| 1806 | cpu_helper->cpu_mask = NULL; | ||
| 1807 | } | ||
| 1808 | |||
| 1809 | cpu_helper->func(TRUE, cpu_helper->allcpus, cpu_mask, cpu_helper->data); | ||
| 1810 | break; | ||
| 1811 | |||
| 1812 | case GTK_RESPONSE_REJECT: | ||
| 1813 | cpu_helper->func(FALSE, FALSE, NULL, cpu_helper->data); | ||
| 1814 | break; | ||
| 1815 | default: | ||
| 1816 | break; | ||
| 1817 | }; | ||
| 1818 | |||
| 1819 | g_free(cpu_mask); | ||
| 1820 | |||
| 1821 | gtk_widget_destroy(GTK_WIDGET(helper->dialog)); | ||
| 1822 | |||
| 1823 | destroy_cpu_helper(helper->data); | ||
| 1824 | g_free(helper); | ||
| 1825 | } | ||
| 1826 | |||
| 1827 | #define CPU_ALL_CPUS_STR "All CPUs" | 1682 | #define CPU_ALL_CPUS_STR "All CPUs" |
| 1828 | 1683 | ||
| 1829 | void cpu_toggle(gpointer data, GtkWidget *widget) | 1684 | void cpu_toggle(gpointer data, GtkWidget *widget) |
| @@ -1875,8 +1730,8 @@ void cpu_toggle(gpointer data, GtkWidget *widget) | |||
| 1875 | void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpus_selected, gint cpus, | 1730 | void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpus_selected, gint cpus, |
| 1876 | trace_filter_cpu_cb_func func, gpointer data) | 1731 | trace_filter_cpu_cb_func func, gpointer data) |
| 1877 | { | 1732 | { |
| 1878 | struct dialog_helper *helper; | ||
| 1879 | struct cpu_filter_helper *cpu_helper; | 1733 | struct cpu_filter_helper *cpu_helper; |
| 1734 | guint64 *cpu_mask = NULL; | ||
| 1880 | GtkWidget *dialog; | 1735 | GtkWidget *dialog; |
| 1881 | GtkWidget *scrollwin; | 1736 | GtkWidget *scrollwin; |
| 1882 | GtkWidget *viewport; | 1737 | GtkWidget *viewport; |
| @@ -1888,15 +1743,11 @@ void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpus_selected, gint cpu | |||
| 1888 | gint width, height; | 1743 | gint width, height; |
| 1889 | gint allset; | 1744 | gint allset; |
| 1890 | gint cpu; | 1745 | gint cpu; |
| 1891 | 1746 | int result; | |
| 1892 | helper = g_malloc(sizeof(*helper)); | ||
| 1893 | g_assert(helper != NULL); | ||
| 1894 | 1747 | ||
| 1895 | cpu_helper = g_new0(typeof(*cpu_helper), 1); | 1748 | cpu_helper = g_new0(typeof(*cpu_helper), 1); |
| 1896 | g_assert(cpu_helper != NULL); | 1749 | g_assert(cpu_helper != NULL); |
| 1897 | 1750 | ||
| 1898 | helper->data = cpu_helper; | ||
| 1899 | |||
| 1900 | /* --- Make dialog window --- */ | 1751 | /* --- Make dialog window --- */ |
| 1901 | 1752 | ||
| 1902 | dialog = gtk_dialog_new_with_buttons("Filter CPUS", | 1753 | dialog = gtk_dialog_new_with_buttons("Filter CPUS", |
| @@ -1908,19 +1759,10 @@ void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpus_selected, gint cpu | |||
| 1908 | GTK_RESPONSE_REJECT, | 1759 | GTK_RESPONSE_REJECT, |
| 1909 | NULL); | 1760 | NULL); |
| 1910 | 1761 | ||
| 1911 | helper->dialog = dialog; | ||
| 1912 | |||
| 1913 | cpu_helper->cpus = cpus; | 1762 | cpu_helper->cpus = cpus; |
| 1914 | cpu_helper->buttons = g_new0(GtkWidget *, cpus + 1); | 1763 | cpu_helper->buttons = g_new0(GtkWidget *, cpus + 1); |
| 1915 | g_assert(cpu_helper->buttons); | 1764 | g_assert(cpu_helper->buttons); |
| 1916 | 1765 | ||
| 1917 | cpu_helper->func = func; | ||
| 1918 | cpu_helper->data = data; | ||
| 1919 | |||
| 1920 | g_signal_connect_swapped (dialog, "response", | ||
| 1921 | G_CALLBACK (cpu_dialog_response), | ||
| 1922 | (gpointer) helper); | ||
| 1923 | |||
| 1924 | scrollwin = gtk_scrolled_window_new(NULL, NULL); | 1766 | scrollwin = gtk_scrolled_window_new(NULL, NULL); |
| 1925 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | 1767 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), |
| 1926 | GTK_POLICY_AUTOMATIC, | 1768 | GTK_POLICY_AUTOMATIC, |
| @@ -2012,6 +1854,31 @@ void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpus_selected, gint cpu | |||
| 2012 | width, height); | 1854 | width, height); |
| 2013 | 1855 | ||
| 2014 | gtk_widget_show_all(dialog); | 1856 | gtk_widget_show_all(dialog); |
| 1857 | |||
| 1858 | result = gtk_dialog_run(GTK_DIALOG(dialog)); | ||
| 1859 | switch (result) { | ||
| 1860 | case GTK_RESPONSE_ACCEPT: | ||
| 1861 | |||
| 1862 | if (!cpu_helper->allcpus) { | ||
| 1863 | cpu_mask = cpu_helper->cpu_mask; | ||
| 1864 | cpu_helper->cpu_mask = NULL; | ||
| 1865 | } | ||
| 1866 | |||
| 1867 | func(TRUE, cpu_helper->allcpus, cpu_mask, data); | ||
| 1868 | break; | ||
| 1869 | |||
| 1870 | case GTK_RESPONSE_REJECT: | ||
| 1871 | func(FALSE, FALSE, NULL, data); | ||
| 1872 | break; | ||
| 1873 | default: | ||
| 1874 | break; | ||
| 1875 | }; | ||
| 1876 | |||
| 1877 | g_free(cpu_mask); | ||
| 1878 | |||
| 1879 | gtk_widget_destroy(dialog); | ||
| 1880 | |||
| 1881 | destroy_cpu_helper(cpu_helper); | ||
| 2015 | } | 1882 | } |
| 2016 | 1883 | ||
| 2017 | static void add_system_str(gchar ***systems, char *system, int count) | 1884 | static void add_system_str(gchar ***systems, char *system, int count) |
| @@ -2158,3 +2025,236 @@ void trace_filter_convert_char_to_filter(struct event_filter *filter, | |||
| 2158 | 2025 | ||
| 2159 | pevent_filter_free(copy); | 2026 | pevent_filter_free(copy); |
| 2160 | } | 2027 | } |
| 2028 | |||
| 2029 | int trace_filter_save_events(struct tracecmd_xml_handle *handle, | ||
| 2030 | struct event_filter *filter) | ||
| 2031 | { | ||
| 2032 | struct event_format *event; | ||
| 2033 | char **systems; | ||
| 2034 | gint *event_ids; | ||
| 2035 | char *str; | ||
| 2036 | int i; | ||
| 2037 | |||
| 2038 | trace_filter_convert_filter_to_names(filter, &systems, | ||
| 2039 | &event_ids); | ||
| 2040 | |||
| 2041 | for (i = 0; systems && systems[i]; i++) | ||
| 2042 | tracecmd_xml_write_element(handle, "System", systems[i]); | ||
| 2043 | |||
| 2044 | for (i = 0; event_ids && event_ids[i] > 0; i++) { | ||
| 2045 | str = pevent_filter_make_string(filter, event_ids[i]); | ||
| 2046 | if (!str) | ||
| 2047 | continue; | ||
| 2048 | |||
| 2049 | event = pevent_find_event(filter->pevent, event_ids[i]); | ||
| 2050 | if (event) { | ||
| 2051 | |||
| 2052 | /* skip not filtered items */ | ||
| 2053 | if (strcmp(str, "FALSE") == 0) { | ||
| 2054 | free(str); | ||
| 2055 | continue; | ||
| 2056 | } | ||
| 2057 | |||
| 2058 | tracecmd_xml_start_sub_system(handle, "Event"); | ||
| 2059 | tracecmd_xml_write_element(handle, "System", event->system); | ||
| 2060 | tracecmd_xml_write_element(handle, "Name", event->name); | ||
| 2061 | /* If this is has an advanced filter, include that too */ | ||
| 2062 | if (strcmp(str, "TRUE") != 0) { | ||
| 2063 | tracecmd_xml_write_element(handle, "Advanced", | ||
| 2064 | str); | ||
| 2065 | } | ||
| 2066 | tracecmd_xml_end_sub_system(handle); | ||
| 2067 | } | ||
| 2068 | free(str); | ||
| 2069 | } | ||
| 2070 | |||
| 2071 | return 0; | ||
| 2072 | } | ||
| 2073 | |||
| 2074 | int trace_filter_save_tasks(struct tracecmd_xml_handle *handle, | ||
| 2075 | struct filter_task *filter) | ||
| 2076 | { | ||
| 2077 | char buffer[100]; | ||
| 2078 | int *pids; | ||
| 2079 | int i; | ||
| 2080 | |||
| 2081 | pids = filter_task_pids(filter); | ||
| 2082 | if (!pids) | ||
| 2083 | return -1; | ||
| 2084 | |||
| 2085 | for (i = 0; pids[i] >= 0; i++) { | ||
| 2086 | snprintf(buffer, 100, "%d", pids[i]); | ||
| 2087 | tracecmd_xml_write_element(handle, "Task", buffer); | ||
| 2088 | } | ||
| 2089 | |||
| 2090 | free(pids); | ||
| 2091 | |||
| 2092 | return 0; | ||
| 2093 | } | ||
| 2094 | |||
| 2095 | int trace_filter_load_events(struct event_filter *event_filter, | ||
| 2096 | struct tracecmd_xml_handle *handle, | ||
| 2097 | struct tracecmd_xml_system_node *node) | ||
| 2098 | { | ||
| 2099 | struct tracecmd_xml_system_node *child; | ||
| 2100 | const char *name; | ||
| 2101 | const char *system; | ||
| 2102 | const char *event; | ||
| 2103 | const char *value; | ||
| 2104 | char *buffer; | ||
| 2105 | |||
| 2106 | while (node) { | ||
| 2107 | name = tracecmd_xml_node_type(node); | ||
| 2108 | |||
| 2109 | if (strcmp(name, "System") == 0) { | ||
| 2110 | system = tracecmd_xml_node_value(handle, node); | ||
| 2111 | pevent_filter_add_filter_str(event_filter, | ||
| 2112 | system, NULL); | ||
| 2113 | } else if (strcmp(name, "Event") == 0) { | ||
| 2114 | system = NULL; | ||
| 2115 | event = NULL; | ||
| 2116 | value = NULL; | ||
| 2117 | child = tracecmd_xml_node_child(node); | ||
| 2118 | if (!child) | ||
| 2119 | return -1; | ||
| 2120 | do { | ||
| 2121 | name = tracecmd_xml_node_type(child); | ||
| 2122 | if (strcmp(name, "System") == 0) | ||
| 2123 | system = tracecmd_xml_node_value(handle, child); | ||
| 2124 | else if (strcmp(name, "Name") == 0) | ||
| 2125 | event = tracecmd_xml_node_value(handle, child); | ||
| 2126 | else if (strcmp(name, "Advanced") == 0) | ||
| 2127 | value = tracecmd_xml_node_value(handle, child); | ||
| 2128 | child = tracecmd_xml_node_next(child); | ||
| 2129 | } while (child); | ||
| 2130 | |||
| 2131 | if (event || system) { | ||
| 2132 | if (event && system) { | ||
| 2133 | if (value) { | ||
| 2134 | buffer = malloc_or_die(strlen(event) + | ||
| 2135 | strlen(system) + | ||
| 2136 | strlen(value) + 3); | ||
| 2137 | sprintf(buffer, "%s/%s:%s", | ||
| 2138 | system, event, value); | ||
| 2139 | } else { | ||
| 2140 | buffer = malloc_or_die(strlen(event) + | ||
| 2141 | strlen(system) + 2); | ||
| 2142 | sprintf(buffer, "%s/%s", | ||
| 2143 | system, event); | ||
| 2144 | } | ||
| 2145 | } else { | ||
| 2146 | if (!event) | ||
| 2147 | event = system; | ||
| 2148 | if (value) { | ||
| 2149 | buffer = malloc_or_die(strlen(event) + | ||
| 2150 | strlen(value) + 2); | ||
| 2151 | sprintf(buffer, "%s:%s", | ||
| 2152 | event, value); | ||
| 2153 | } else { | ||
| 2154 | buffer = malloc_or_die(strlen(event) + 1); | ||
| 2155 | sprintf(buffer, "%s", event); | ||
| 2156 | } | ||
| 2157 | } | ||
| 2158 | pevent_filter_add_filter_str(event_filter, | ||
| 2159 | buffer, NULL); | ||
| 2160 | free(buffer); | ||
| 2161 | } | ||
| 2162 | } | ||
| 2163 | |||
| 2164 | node = tracecmd_xml_node_next(node); | ||
| 2165 | } | ||
| 2166 | |||
| 2167 | return 0; | ||
| 2168 | } | ||
| 2169 | |||
| 2170 | int trace_filter_load_task_filter(struct filter_task *filter, | ||
| 2171 | struct tracecmd_xml_handle *handle, | ||
| 2172 | struct tracecmd_xml_system_node *node) | ||
| 2173 | { | ||
| 2174 | const char *name; | ||
| 2175 | const char *task; | ||
| 2176 | int pid; | ||
| 2177 | |||
| 2178 | if (!filter) | ||
| 2179 | return 0; | ||
| 2180 | |||
| 2181 | node = tracecmd_xml_node_child(node); | ||
| 2182 | |||
| 2183 | while (node) { | ||
| 2184 | name = tracecmd_xml_node_type(node); | ||
| 2185 | |||
| 2186 | if (strcmp(name, "Task") == 0) { | ||
| 2187 | task = tracecmd_xml_node_value(handle, node); | ||
| 2188 | pid = atoi(task); | ||
| 2189 | if (!filter_task_find_pid(filter, pid)) | ||
| 2190 | filter_task_add_pid(filter, pid); | ||
| 2191 | } | ||
| 2192 | node = tracecmd_xml_node_next(node); | ||
| 2193 | } | ||
| 2194 | |||
| 2195 | return 0; | ||
| 2196 | } | ||
| 2197 | |||
| 2198 | int trace_filter_load_filters(struct tracecmd_xml_handle *handle, | ||
| 2199 | const char *system_name, | ||
| 2200 | struct filter_task *task_filter, | ||
| 2201 | struct filter_task *hide_tasks) | ||
| 2202 | { | ||
| 2203 | struct tracecmd_xml_system *system; | ||
| 2204 | struct tracecmd_xml_system_node *syschild; | ||
| 2205 | const char *name; | ||
| 2206 | |||
| 2207 | system = tracecmd_xml_find_system(handle, system_name); | ||
| 2208 | if (!system) | ||
| 2209 | return -1; | ||
| 2210 | |||
| 2211 | |||
| 2212 | syschild = tracecmd_xml_system_node(system); | ||
| 2213 | if (!syschild) | ||
| 2214 | goto out_free_sys; | ||
| 2215 | |||
| 2216 | do { | ||
| 2217 | name = tracecmd_xml_node_type(syschild); | ||
| 2218 | |||
| 2219 | if (strcmp(name, "TaskFilter") == 0) | ||
| 2220 | trace_filter_load_task_filter(task_filter, handle, syschild); | ||
| 2221 | |||
| 2222 | else if (strcmp(name, "HideTasks") == 0) | ||
| 2223 | trace_filter_load_task_filter(hide_tasks, handle, syschild); | ||
| 2224 | |||
| 2225 | syschild = tracecmd_xml_node_next(syschild); | ||
| 2226 | } while (syschild); | ||
| 2227 | |||
| 2228 | tracecmd_xml_free_system(system); | ||
| 2229 | |||
| 2230 | return 0; | ||
| 2231 | |||
| 2232 | out_free_sys: | ||
| 2233 | tracecmd_xml_free_system(system); | ||
| 2234 | return -1; | ||
| 2235 | } | ||
| 2236 | |||
| 2237 | int trace_filter_save_filters(struct tracecmd_xml_handle *handle, | ||
| 2238 | const char *system_name, | ||
| 2239 | struct filter_task *task_filter, | ||
| 2240 | struct filter_task *hide_tasks) | ||
| 2241 | { | ||
| 2242 | |||
| 2243 | tracecmd_xml_start_system(handle, system_name); | ||
| 2244 | |||
| 2245 | if (task_filter && filter_task_count(task_filter)) { | ||
| 2246 | tracecmd_xml_start_sub_system(handle, "TaskFilter"); | ||
| 2247 | trace_filter_save_tasks(handle, task_filter); | ||
| 2248 | tracecmd_xml_end_sub_system(handle); | ||
| 2249 | } | ||
| 2250 | |||
| 2251 | if (hide_tasks && filter_task_count(hide_tasks)) { | ||
| 2252 | tracecmd_xml_start_sub_system(handle, "HideTasks"); | ||
| 2253 | trace_filter_save_tasks(handle, hide_tasks); | ||
| 2254 | tracecmd_xml_end_sub_system(handle); | ||
| 2255 | } | ||
| 2256 | |||
| 2257 | tracecmd_xml_end_system(handle); | ||
| 2258 | |||
| 2259 | return 0; | ||
| 2260 | } | ||
diff --git a/trace-filter.h b/trace-filter.h index c68e8f0..1800471 100644 --- a/trace-filter.h +++ b/trace-filter.h | |||
| @@ -23,6 +23,8 @@ | |||
| 23 | 23 | ||
| 24 | #include <gtk/gtk.h> | 24 | #include <gtk/gtk.h> |
| 25 | 25 | ||
| 26 | #include "trace-xml.h" | ||
| 27 | |||
| 26 | struct event_filter_list { | 28 | struct event_filter_list { |
| 27 | struct event_filter_list *next; | 29 | struct event_filter_list *next; |
| 28 | struct event *event; | 30 | struct event *event; |
| @@ -133,11 +135,31 @@ typedef void (*trace_filter_cpu_cb_func)(gboolean accept, | |||
| 133 | void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpu_mask_selected, gint cpus, | 135 | void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpu_mask_selected, gint cpus, |
| 134 | trace_filter_cpu_cb_func func, gpointer data); | 136 | trace_filter_cpu_cb_func func, gpointer data); |
| 135 | 137 | ||
| 138 | void trace_array_add(gint **array, gint *count, gint val); | ||
| 139 | |||
| 140 | /* save and load filters */ | ||
| 141 | int trace_filter_save_events(struct tracecmd_xml_handle *handle, | ||
| 142 | struct event_filter *filter); | ||
| 143 | int trace_filter_save_tasks(struct tracecmd_xml_handle *handle, | ||
| 144 | struct filter_task *filter); | ||
| 145 | int trace_filter_load_events(struct event_filter *event_filter, | ||
| 146 | struct tracecmd_xml_handle *handle, | ||
| 147 | struct tracecmd_xml_system_node *node); | ||
| 148 | int trace_filter_load_task_filter(struct filter_task *filter, | ||
| 149 | struct tracecmd_xml_handle *handle, | ||
| 150 | struct tracecmd_xml_system_node *node); | ||
| 151 | int trace_filter_load_filters(struct tracecmd_xml_handle *handle, | ||
| 152 | const char *system_name, | ||
| 153 | struct filter_task *task_filter, | ||
| 154 | struct filter_task *hide_tasks); | ||
| 155 | int trace_filter_save_filters(struct tracecmd_xml_handle *handle, | ||
| 156 | const char *system_name, | ||
| 157 | struct filter_task *task_filter, | ||
| 158 | struct filter_task *hide_tasks); | ||
| 159 | |||
| 136 | /* put here because there's no other place */ | 160 | /* put here because there's no other place */ |
| 137 | 161 | ||
| 138 | int str_cmp(const void *a, const void *b); | 162 | int str_cmp(const void *a, const void *b); |
| 139 | int id_cmp(const void *a, const void *b); | 163 | int id_cmp(const void *a, const void *b); |
| 140 | 164 | ||
| 141 | void trace_array_add(gint **array, gint *count, gint val); | ||
| 142 | |||
| 143 | #endif /* _TRACE_FILTER_H */ | 165 | #endif /* _TRACE_FILTER_H */ |
diff --git a/trace-graph-main.c b/trace-graph-main.c index b373dd2..b4f05fb 100644 --- a/trace-graph-main.c +++ b/trace-graph-main.c | |||
| @@ -29,6 +29,9 @@ | |||
| 29 | #include "trace-cmd.h" | 29 | #include "trace-cmd.h" |
| 30 | #include "trace-graph.h" | 30 | #include "trace-graph.h" |
| 31 | #include "trace-filter.h" | 31 | #include "trace-filter.h" |
| 32 | #include "trace-gui.h" | ||
| 33 | |||
| 34 | #include "version.h" | ||
| 32 | 35 | ||
| 33 | #define version "0.1.1" | 36 | #define version "0.1.1" |
| 34 | 37 | ||
| @@ -52,26 +55,19 @@ load_clicked (gpointer data) | |||
| 52 | { | 55 | { |
| 53 | struct graph_info *ginfo = data; | 56 | struct graph_info *ginfo = data; |
| 54 | struct tracecmd_input *handle; | 57 | struct tracecmd_input *handle; |
| 55 | GtkWidget *dialog; | ||
| 56 | gchar *filename; | 58 | gchar *filename; |
| 57 | 59 | ||
| 58 | dialog = gtk_file_chooser_dialog_new("Load File", | 60 | filename = trace_get_file_dialog("Load File"); |
| 59 | NULL, | 61 | if (!filename) |
| 60 | GTK_FILE_CHOOSER_ACTION_OPEN, | 62 | return; |
| 61 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | 63 | |
| 62 | GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, | 64 | handle = tracecmd_open(filename); |
| 63 | NULL); | 65 | if (handle) { |
| 64 | if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { | 66 | trace_graph_load_handle(ginfo, handle); |
| 65 | filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); | 67 | /* Free handle when freeing graph */ |
| 66 | handle = tracecmd_open(filename); | 68 | tracecmd_close(handle); |
| 67 | if (handle) { | ||
| 68 | trace_graph_load_handle(ginfo, handle); | ||
| 69 | /* Free handle when freeing graph */ | ||
| 70 | tracecmd_close(handle); | ||
| 71 | } | ||
| 72 | g_free(filename); | ||
| 73 | } | 69 | } |
| 74 | gtk_widget_destroy(dialog); | 70 | g_free(filename); |
| 75 | } | 71 | } |
| 76 | 72 | ||
| 77 | /* Callback for the clicked signal of the Exit button */ | 73 | /* Callback for the clicked signal of the Exit button */ |
| @@ -158,6 +154,60 @@ plot_tasks_clicked (gpointer data) | |||
| 158 | free(selected); | 154 | free(selected); |
| 159 | } | 155 | } |
| 160 | 156 | ||
| 157 | /* Callback for the clicked signal of the Load Filters button */ | ||
| 158 | static void | ||
| 159 | load_filters_clicked (gpointer data) | ||
| 160 | { | ||
| 161 | struct graph_info *ginfo = data; | ||
| 162 | struct tracecmd_xml_handle *handle; | ||
| 163 | gchar *filename; | ||
| 164 | |||
| 165 | filename = trace_get_file_dialog("Load Filters"); | ||
| 166 | if (!filename) | ||
| 167 | return; | ||
| 168 | |||
| 169 | handle = tracecmd_xml_open(filename); | ||
| 170 | if (!handle) | ||
| 171 | warning("Could not open %s", filename); | ||
| 172 | g_free(filename); | ||
| 173 | |||
| 174 | trace_filter_load_filters(handle, | ||
| 175 | "GraphTaskFilter", | ||
| 176 | ginfo->task_filter, | ||
| 177 | ginfo->hide_tasks); | ||
| 178 | |||
| 179 | trace_graph_load_filters(ginfo, handle); | ||
| 180 | |||
| 181 | tracecmd_xml_close(handle); | ||
| 182 | } | ||
| 183 | |||
| 184 | /* Callback for the clicked signal of the Save Filters button */ | ||
| 185 | static void | ||
| 186 | save_filters_clicked (gpointer data) | ||
| 187 | { | ||
| 188 | struct graph_info *ginfo = data; | ||
| 189 | struct tracecmd_xml_handle *handle; | ||
| 190 | gchar *filename; | ||
| 191 | |||
| 192 | filename = trace_get_file_dialog("Save Filters"); | ||
| 193 | if (!filename) | ||
| 194 | return; | ||
| 195 | |||
| 196 | handle = tracecmd_xml_create(filename, VERSION_STRING); | ||
| 197 | if (!handle) | ||
| 198 | warning("Could not create %s", filename); | ||
| 199 | g_free(filename); | ||
| 200 | |||
| 201 | trace_filter_save_filters(handle, | ||
| 202 | "GraphTaskFilter", | ||
| 203 | ginfo->task_filter, | ||
| 204 | ginfo->hide_tasks); | ||
| 205 | |||
| 206 | trace_graph_save_filters(ginfo, handle); | ||
| 207 | |||
| 208 | tracecmd_xml_close(handle); | ||
| 209 | } | ||
| 210 | |||
| 161 | void trace_graph(int argc, char **argv) | 211 | void trace_graph(int argc, char **argv) |
| 162 | { | 212 | { |
| 163 | struct tracecmd_input *handle = NULL; | 213 | struct tracecmd_input *handle = NULL; |
| @@ -170,6 +220,7 @@ void trace_graph(int argc, char **argv) | |||
| 170 | GtkWidget *menu_item; | 220 | GtkWidget *menu_item; |
| 171 | GtkWidget *sub_item; | 221 | GtkWidget *sub_item; |
| 172 | GtkWidget *widget; | 222 | GtkWidget *widget; |
| 223 | GtkWidget *statusbar; | ||
| 173 | int c; | 224 | int c; |
| 174 | int ret; | 225 | int ret; |
| 175 | 226 | ||
| @@ -215,6 +266,8 @@ void trace_graph(int argc, char **argv) | |||
| 215 | 266 | ||
| 216 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | 267 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
| 217 | 268 | ||
| 269 | trace_dialog_register_window(window); | ||
| 270 | |||
| 218 | /* --- Top Level Vbox --- */ | 271 | /* --- Top Level Vbox --- */ |
| 219 | 272 | ||
| 220 | vbox = gtk_vbox_new(FALSE, 0); | 273 | vbox = gtk_vbox_new(FALSE, 0); |
| @@ -253,6 +306,35 @@ void trace_graph(int argc, char **argv) | |||
| 253 | gtk_widget_show(sub_item); | 306 | gtk_widget_show(sub_item); |
| 254 | 307 | ||
| 255 | 308 | ||
| 309 | /* --- File - Load Filter Option --- */ | ||
| 310 | |||
| 311 | sub_item = gtk_menu_item_new_with_label("Load filters"); | ||
| 312 | |||
| 313 | /* Add them to the menu */ | ||
| 314 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 315 | |||
| 316 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 317 | G_CALLBACK (load_filters_clicked), | ||
| 318 | (gpointer) ginfo); | ||
| 319 | |||
| 320 | /* We do need to show menu items */ | ||
| 321 | gtk_widget_show(sub_item); | ||
| 322 | |||
| 323 | |||
| 324 | /* --- File - Save Filter Option --- */ | ||
| 325 | |||
| 326 | sub_item = gtk_menu_item_new_with_label("Save filters"); | ||
| 327 | |||
| 328 | /* Add them to the menu */ | ||
| 329 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 330 | |||
| 331 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 332 | G_CALLBACK (save_filters_clicked), | ||
| 333 | (gpointer) ginfo); | ||
| 334 | |||
| 335 | /* We do need to show menu items */ | ||
| 336 | gtk_widget_show(sub_item); | ||
| 337 | |||
| 256 | /* --- File - Quit Option --- */ | 338 | /* --- File - Quit Option --- */ |
| 257 | 339 | ||
| 258 | sub_item = gtk_menu_item_new_with_label("Quit"); | 340 | sub_item = gtk_menu_item_new_with_label("Quit"); |
| @@ -380,6 +462,14 @@ void trace_graph(int argc, char **argv) | |||
| 380 | gtk_widget_show(widget); | 462 | gtk_widget_show(widget); |
| 381 | 463 | ||
| 382 | 464 | ||
| 465 | /* --- Set up Status Bar --- */ | ||
| 466 | |||
| 467 | statusbar = trace_status_bar_new(); | ||
| 468 | |||
| 469 | gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); | ||
| 470 | gtk_widget_show(statusbar); | ||
| 471 | |||
| 472 | |||
| 383 | /********************************************** | 473 | /********************************************** |
| 384 | * Main Window | 474 | * Main Window |
| 385 | **********************************************/ | 475 | **********************************************/ |
diff --git a/trace-graph.c b/trace-graph.c index 6ed7851..04e2439 100644 --- a/trace-graph.c +++ b/trace-graph.c | |||
| @@ -548,6 +548,44 @@ void trace_graph_clear_tasks(struct graph_info *ginfo) | |||
| 548 | redraw_graph(ginfo); | 548 | redraw_graph(ginfo); |
| 549 | } | 549 | } |
| 550 | 550 | ||
| 551 | void trace_graph_update_filters(struct graph_info *ginfo, | ||
| 552 | struct filter_task *task_filter, | ||
| 553 | struct filter_task *hide_tasks) | ||
| 554 | { | ||
| 555 | /* Make sure the filter passed in is not the filter we use */ | ||
| 556 | if (task_filter != ginfo->task_filter) { | ||
| 557 | filter_task_hash_free(ginfo->task_filter); | ||
| 558 | ginfo->task_filter = filter_task_hash_copy(task_filter); | ||
| 559 | } | ||
| 560 | |||
| 561 | if (hide_tasks != ginfo->hide_tasks) { | ||
| 562 | filter_task_hash_free(ginfo->hide_tasks); | ||
| 563 | ginfo->hide_tasks = filter_task_hash_copy(hide_tasks); | ||
| 564 | } | ||
| 565 | |||
| 566 | if (ginfo->callbacks && ginfo->callbacks->filter) | ||
| 567 | ginfo->callbacks->filter(ginfo, ginfo->task_filter, | ||
| 568 | ginfo->hide_tasks); | ||
| 569 | |||
| 570 | if (ginfo->filter_enabled) | ||
| 571 | redraw_graph(ginfo); | ||
| 572 | |||
| 573 | if (filter_task_count(ginfo->task_filter) || | ||
| 574 | filter_task_count(ginfo->hide_tasks)) | ||
| 575 | ginfo->filter_available = 1; | ||
| 576 | else { | ||
| 577 | ginfo->filter_enabled = 0; | ||
| 578 | ginfo->filter_available = 0; | ||
| 579 | } | ||
| 580 | |||
| 581 | } | ||
| 582 | |||
| 583 | void trace_graph_refresh_filters(struct graph_info *ginfo) | ||
| 584 | { | ||
| 585 | trace_graph_update_filters(ginfo, ginfo->task_filter, | ||
| 586 | ginfo->hide_tasks); | ||
| 587 | } | ||
| 588 | |||
| 551 | static void | 589 | static void |
| 552 | filter_clear_tasks_clicked (gpointer data) | 590 | filter_clear_tasks_clicked (gpointer data) |
| 553 | { | 591 | { |
| @@ -718,7 +756,7 @@ do_pop_up(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 718 | g_assert(text); | 756 | g_assert(text); |
| 719 | 757 | ||
| 720 | if (trace_graph_filter_task_find_pid(ginfo, pid)) | 758 | if (trace_graph_filter_task_find_pid(ginfo, pid)) |
| 721 | snprintf(text, len, "Remove %s-%d to filter", comm, pid); | 759 | snprintf(text, len, "Remove %s-%d from filter", comm, pid); |
| 722 | else | 760 | else |
| 723 | snprintf(text, len, "Add %s-%d to filter", comm, pid); | 761 | snprintf(text, len, "Add %s-%d to filter", comm, pid); |
| 724 | 762 | ||
| @@ -728,9 +766,9 @@ do_pop_up(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 728 | text); | 766 | text); |
| 729 | 767 | ||
| 730 | if (trace_graph_hide_task_find_pid(ginfo, pid)) | 768 | if (trace_graph_hide_task_find_pid(ginfo, pid)) |
| 731 | snprintf(text, len, "Show %s-%d to filter", comm, pid); | 769 | snprintf(text, len, "Show %s-%d", comm, pid); |
| 732 | else | 770 | else |
| 733 | snprintf(text, len, "Hide %s-%d to filter", comm, pid); | 771 | snprintf(text, len, "Hide %s-%d", comm, pid); |
| 734 | 772 | ||
| 735 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_hide_task), | 773 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_hide_task), |
| 736 | text); | 774 | text); |
| @@ -752,7 +790,7 @@ do_pop_up(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 752 | gtk_widget_set_sensitive(menu_filter_add_task, FALSE); | 790 | gtk_widget_set_sensitive(menu_filter_add_task, FALSE); |
| 753 | 791 | ||
| 754 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_hide_task), | 792 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_hide_task), |
| 755 | "Hide task to filter"); | 793 | "Hide task"); |
| 756 | gtk_widget_set_sensitive(menu_filter_hide_task, FALSE); | 794 | gtk_widget_set_sensitive(menu_filter_hide_task, FALSE); |
| 757 | 795 | ||
| 758 | gtk_widget_hide(menu_plot_task); | 796 | gtk_widget_hide(menu_plot_task); |
| @@ -766,7 +804,25 @@ do_pop_up(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 766 | return TRUE; | 804 | return TRUE; |
| 767 | } | 805 | } |
| 768 | 806 | ||
| 769 | static void button_press(struct graph_info *ginfo, gint x, guint state) | 807 | static void draw_info_box(struct graph_info *ginfo, const gchar *buffer, |
| 808 | gint x, gint y); | ||
| 809 | |||
| 810 | static void stop_zoom_tip(struct graph_info *ginfo) | ||
| 811 | { | ||
| 812 | clear_info_box(ginfo); | ||
| 813 | } | ||
| 814 | |||
| 815 | static void show_zoom_tip(struct graph_info *ginfo, gint x, gint y) | ||
| 816 | { | ||
| 817 | clear_info_box(ginfo); | ||
| 818 | |||
| 819 | draw_info_box(ginfo, | ||
| 820 | "Click and hold left mouse and drag right to zoom in\n" | ||
| 821 | "Click and hold left mouse and drag left to zoom out", | ||
| 822 | x, y); | ||
| 823 | } | ||
| 824 | |||
| 825 | static void button_press(struct graph_info *ginfo, gint x, gint y, guint state) | ||
| 770 | { | 826 | { |
| 771 | ginfo->press_x = x; | 827 | ginfo->press_x = x; |
| 772 | ginfo->last_x = 0; | 828 | ginfo->last_x = 0; |
| @@ -785,8 +841,10 @@ static void button_press(struct graph_info *ginfo, gint x, guint state) | |||
| 785 | clear_line(ginfo, convert_time_to_x(ginfo, ginfo->marka_time)); | 841 | clear_line(ginfo, convert_time_to_x(ginfo, ginfo->marka_time)); |
| 786 | update_marka(ginfo, x); | 842 | update_marka(ginfo, x); |
| 787 | } | 843 | } |
| 788 | } else | 844 | } else { |
| 789 | ginfo->zoom = TRUE; | 845 | ginfo->zoom = TRUE; |
| 846 | show_zoom_tip(ginfo, x, y); | ||
| 847 | } | ||
| 790 | 848 | ||
| 791 | return; | 849 | return; |
| 792 | } | 850 | } |
| @@ -807,6 +865,7 @@ button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 807 | 865 | ||
| 808 | /* check for double click */ | 866 | /* check for double click */ |
| 809 | if (event->type == GDK_2BUTTON_PRESS) { | 867 | if (event->type == GDK_2BUTTON_PRESS) { |
| 868 | stop_zoom_tip(ginfo); | ||
| 810 | if (ginfo->line_active) { | 869 | if (ginfo->line_active) { |
| 811 | ginfo->line_active = FALSE; | 870 | ginfo->line_active = FALSE; |
| 812 | clear_line(ginfo, ginfo->last_x); | 871 | clear_line(ginfo, ginfo->last_x); |
| @@ -826,7 +885,7 @@ button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 826 | return TRUE; | 885 | return TRUE; |
| 827 | } | 886 | } |
| 828 | 887 | ||
| 829 | button_press(ginfo, event->x, event->state); | 888 | button_press(ginfo, event->x, event->y, event->state); |
| 830 | 889 | ||
| 831 | return TRUE; | 890 | return TRUE; |
| 832 | } | 891 | } |
| @@ -839,6 +898,9 @@ static void motion_plot(struct graph_info *ginfo, gint x, gint y) | |||
| 839 | { | 898 | { |
| 840 | struct graph_plot *plot; | 899 | struct graph_plot *plot; |
| 841 | 900 | ||
| 901 | if (ginfo->zoom) | ||
| 902 | stop_zoom_tip(ginfo); | ||
| 903 | |||
| 842 | if (!ginfo->curr_pixmap) | 904 | if (!ginfo->curr_pixmap) |
| 843 | return; | 905 | return; |
| 844 | 906 | ||
| @@ -876,7 +938,7 @@ info_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) | |||
| 876 | if (event->type == GDK_2BUTTON_PRESS) | 938 | if (event->type == GDK_2BUTTON_PRESS) |
| 877 | return FALSE; | 939 | return FALSE; |
| 878 | 940 | ||
| 879 | button_press(ginfo, gtk_adjustment_get_value(ginfo->hadj), event->state); | 941 | button_press(ginfo, gtk_adjustment_get_value(ginfo->hadj), event->y, event->state); |
| 880 | 942 | ||
| 881 | return FALSE; | 943 | return FALSE; |
| 882 | } | 944 | } |
| @@ -1500,7 +1562,8 @@ static void button_release(struct graph_info *ginfo, gint x) | |||
| 1500 | ginfo->show_marka = TRUE; | 1562 | ginfo->show_marka = TRUE; |
| 1501 | ginfo->show_markb = TRUE; | 1563 | ginfo->show_markb = TRUE; |
| 1502 | update_markb(ginfo, x); | 1564 | update_markb(ginfo, x); |
| 1503 | } | 1565 | } else |
| 1566 | stop_zoom_tip(ginfo); | ||
| 1504 | 1567 | ||
| 1505 | clear_line(ginfo, ginfo->last_x); | 1568 | clear_line(ginfo, ginfo->last_x); |
| 1506 | clear_line(ginfo, ginfo->press_x); | 1569 | clear_line(ginfo, ginfo->press_x); |
| @@ -2395,6 +2458,132 @@ int trace_graph_load_handle(struct graph_info *ginfo, | |||
| 2395 | return 0; | 2458 | return 0; |
| 2396 | } | 2459 | } |
| 2397 | 2460 | ||
| 2461 | static int load_event_filter(struct graph_info *ginfo, | ||
| 2462 | struct tracecmd_xml_handle *handle, | ||
| 2463 | struct tracecmd_xml_system_node *node) | ||
| 2464 | { | ||
| 2465 | struct tracecmd_xml_system_node *child; | ||
| 2466 | struct event_filter *event_filter; | ||
| 2467 | const char *name; | ||
| 2468 | const char *value; | ||
| 2469 | |||
| 2470 | event_filter = ginfo->event_filter; | ||
| 2471 | |||
| 2472 | child = tracecmd_xml_node_child(node); | ||
| 2473 | name = tracecmd_xml_node_type(child); | ||
| 2474 | if (strcmp(name, "FilterType") != 0) | ||
| 2475 | return -1; | ||
| 2476 | |||
| 2477 | value = tracecmd_xml_node_value(handle, child); | ||
| 2478 | /* Do nothing with all events enabled */ | ||
| 2479 | if (strcmp(value, "all events") == 0) | ||
| 2480 | return 0; | ||
| 2481 | |||
| 2482 | node = tracecmd_xml_node_next(child); | ||
| 2483 | if (!node) | ||
| 2484 | return -1; | ||
| 2485 | |||
| 2486 | pevent_filter_clear_trivial(event_filter, FILTER_TRIVIAL_BOTH); | ||
| 2487 | ginfo->all_events = FALSE; | ||
| 2488 | |||
| 2489 | trace_filter_load_events(event_filter, handle, node); | ||
| 2490 | |||
| 2491 | return 0; | ||
| 2492 | } | ||
| 2493 | |||
| 2494 | int trace_graph_load_filters(struct graph_info *ginfo, | ||
| 2495 | struct tracecmd_xml_handle *handle) | ||
| 2496 | { | ||
| 2497 | struct tracecmd_xml_system *system; | ||
| 2498 | struct tracecmd_xml_system_node *syschild; | ||
| 2499 | const char *name; | ||
| 2500 | |||
| 2501 | if (filter_task_count(ginfo->task_filter) || | ||
| 2502 | filter_task_count(ginfo->hide_tasks)) | ||
| 2503 | ginfo->filter_available = 1; | ||
| 2504 | else | ||
| 2505 | ginfo->filter_available = 0; | ||
| 2506 | |||
| 2507 | system = tracecmd_xml_find_system(handle, "TraceGraph"); | ||
| 2508 | if (!system) | ||
| 2509 | return -1; | ||
| 2510 | |||
| 2511 | syschild = tracecmd_xml_system_node(system); | ||
| 2512 | if (!syschild) | ||
| 2513 | goto out_free_sys; | ||
| 2514 | |||
| 2515 | do { | ||
| 2516 | name = tracecmd_xml_node_type(syschild); | ||
| 2517 | |||
| 2518 | if (strcmp(name, "EventFilter") == 0) | ||
| 2519 | load_event_filter(ginfo, handle, syschild); | ||
| 2520 | |||
| 2521 | syschild = tracecmd_xml_node_next(syschild); | ||
| 2522 | } while (syschild); | ||
| 2523 | |||
| 2524 | if (filter_task_count(ginfo->task_filter) || | ||
| 2525 | filter_task_count(ginfo->hide_tasks)) | ||
| 2526 | ginfo->filter_available = 1; | ||
| 2527 | else | ||
| 2528 | ginfo->filter_available = 0; | ||
| 2529 | |||
| 2530 | tracecmd_xml_free_system(system); | ||
| 2531 | |||
| 2532 | trace_graph_refresh(ginfo); | ||
| 2533 | |||
| 2534 | return 0; | ||
| 2535 | |||
| 2536 | out_free_sys: | ||
| 2537 | tracecmd_xml_free_system(system); | ||
| 2538 | if (ginfo->filter_enabled) | ||
| 2539 | trace_graph_refresh(ginfo); | ||
| 2540 | |||
| 2541 | return -1; | ||
| 2542 | } | ||
| 2543 | |||
| 2544 | int trace_graph_save_filters(struct graph_info *ginfo, | ||
| 2545 | struct tracecmd_xml_handle *handle) | ||
| 2546 | { | ||
| 2547 | struct event_filter *event_filter; | ||
| 2548 | |||
| 2549 | tracecmd_xml_start_system(handle, "TraceGraph"); | ||
| 2550 | |||
| 2551 | event_filter = ginfo->event_filter; | ||
| 2552 | |||
| 2553 | tracecmd_xml_start_sub_system(handle, "EventFilter"); | ||
| 2554 | |||
| 2555 | if (ginfo->all_events || !event_filter) | ||
| 2556 | tracecmd_xml_write_element(handle, "FilterType", "all events"); | ||
| 2557 | else { | ||
| 2558 | tracecmd_xml_write_element(handle, "FilterType", "filter"); | ||
| 2559 | trace_filter_save_events(handle, event_filter); | ||
| 2560 | } | ||
| 2561 | |||
| 2562 | tracecmd_xml_end_sub_system(handle); | ||
| 2563 | |||
| 2564 | tracecmd_xml_end_system(handle); | ||
| 2565 | |||
| 2566 | return 0; | ||
| 2567 | } | ||
| 2568 | |||
| 2569 | static void set_label_a(GtkWidget *widget) | ||
| 2570 | { | ||
| 2571 | gtk_widget_set_tooltip_text(widget, "Click left mouse on graph\n" | ||
| 2572 | "to set Marker A"); | ||
| 2573 | } | ||
| 2574 | |||
| 2575 | static void set_label_b(GtkWidget *widget) | ||
| 2576 | { | ||
| 2577 | gtk_widget_set_tooltip_text(widget, "Shift and click left mouse on graph\n" | ||
| 2578 | "to set Marker B"); | ||
| 2579 | } | ||
| 2580 | |||
| 2581 | static void set_label_cursor(GtkWidget *widget) | ||
| 2582 | { | ||
| 2583 | gtk_widget_set_tooltip_text(widget, "Double click Left mouse on graph\n" | ||
| 2584 | "to set Cursor"); | ||
| 2585 | } | ||
| 2586 | |||
| 2398 | struct graph_info * | 2587 | struct graph_info * |
| 2399 | trace_graph_create_with_callbacks(struct tracecmd_input *handle, | 2588 | trace_graph_create_with_callbacks(struct tracecmd_input *handle, |
| 2400 | struct graph_callbacks *cbs) | 2589 | struct graph_callbacks *cbs) |
| @@ -2454,11 +2643,13 @@ trace_graph_create_with_callbacks(struct tracecmd_input *handle, | |||
| 2454 | /* --- Cursor --- */ | 2643 | /* --- Cursor --- */ |
| 2455 | 2644 | ||
| 2456 | label = gtk_label_new("Cursor:"); | 2645 | label = gtk_label_new("Cursor:"); |
| 2646 | set_label_cursor(label); | ||
| 2457 | gtk_table_attach(GTK_TABLE(table), label, 4, 5, 0, 1, GTK_EXPAND, GTK_EXPAND, 3, 3); | 2647 | gtk_table_attach(GTK_TABLE(table), label, 4, 5, 0, 1, GTK_EXPAND, GTK_EXPAND, 3, 3); |
| 2458 | gtk_widget_show(label); | 2648 | gtk_widget_show(label); |
| 2459 | 2649 | ||
| 2460 | ginfo->cursor_label = gtk_label_new("0.0"); | 2650 | ginfo->cursor_label = gtk_label_new("0.0"); |
| 2461 | eventbox = gtk_event_box_new(); | 2651 | eventbox = gtk_event_box_new(); |
| 2652 | set_label_cursor(eventbox); | ||
| 2462 | gtk_widget_show(eventbox); | 2653 | gtk_widget_show(eventbox); |
| 2463 | gtk_widget_modify_bg(eventbox, GTK_STATE_NORMAL, &color); | 2654 | gtk_widget_modify_bg(eventbox, GTK_STATE_NORMAL, &color); |
| 2464 | gtk_container_add(GTK_CONTAINER(eventbox), ginfo->cursor_label); | 2655 | gtk_container_add(GTK_CONTAINER(eventbox), ginfo->cursor_label); |
| @@ -2473,9 +2664,11 @@ trace_graph_create_with_callbacks(struct tracecmd_input *handle, | |||
| 2473 | gtk_widget_show(hbox); | 2664 | gtk_widget_show(hbox); |
| 2474 | 2665 | ||
| 2475 | label = gtk_label_new("Marker"); | 2666 | label = gtk_label_new("Marker"); |
| 2667 | set_label_a(label); | ||
| 2476 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | 2668 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); |
| 2477 | gtk_widget_show(label); | 2669 | gtk_widget_show(label); |
| 2478 | 2670 | ||
| 2671 | |||
| 2479 | label = gtk_label_new("A:"); | 2672 | label = gtk_label_new("A:"); |
| 2480 | 2673 | ||
| 2481 | colorAB.red = 0; | 2674 | colorAB.red = 0; |
| @@ -2483,6 +2676,7 @@ trace_graph_create_with_callbacks(struct tracecmd_input *handle, | |||
| 2483 | colorAB.blue = 0; | 2676 | colorAB.blue = 0; |
| 2484 | 2677 | ||
| 2485 | eventbox = gtk_event_box_new(); | 2678 | eventbox = gtk_event_box_new(); |
| 2679 | set_label_a(eventbox); | ||
| 2486 | gtk_widget_show(eventbox); | 2680 | gtk_widget_show(eventbox); |
| 2487 | gtk_widget_modify_bg(eventbox, GTK_STATE_NORMAL, &colorAB); | 2681 | gtk_widget_modify_bg(eventbox, GTK_STATE_NORMAL, &colorAB); |
| 2488 | gtk_container_add(GTK_CONTAINER(eventbox), label); | 2682 | gtk_container_add(GTK_CONTAINER(eventbox), label); |
| @@ -2494,6 +2688,7 @@ trace_graph_create_with_callbacks(struct tracecmd_input *handle, | |||
| 2494 | 2688 | ||
| 2495 | ginfo->marka_label = gtk_label_new("0.0"); | 2689 | ginfo->marka_label = gtk_label_new("0.0"); |
| 2496 | eventbox = gtk_event_box_new(); | 2690 | eventbox = gtk_event_box_new(); |
| 2691 | set_label_a(eventbox); | ||
| 2497 | gtk_widget_show(eventbox); | 2692 | gtk_widget_show(eventbox); |
| 2498 | gtk_widget_modify_bg(eventbox, GTK_STATE_NORMAL, &color); | 2693 | gtk_widget_modify_bg(eventbox, GTK_STATE_NORMAL, &color); |
| 2499 | gtk_container_add(GTK_CONTAINER(eventbox), ginfo->marka_label); | 2694 | gtk_container_add(GTK_CONTAINER(eventbox), ginfo->marka_label); |
| @@ -2508,6 +2703,7 @@ trace_graph_create_with_callbacks(struct tracecmd_input *handle, | |||
| 2508 | gtk_widget_show(hbox); | 2703 | gtk_widget_show(hbox); |
| 2509 | 2704 | ||
| 2510 | label = gtk_label_new("Marker"); | 2705 | label = gtk_label_new("Marker"); |
| 2706 | set_label_b(label); | ||
| 2511 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | 2707 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); |
| 2512 | gtk_widget_show(label); | 2708 | gtk_widget_show(label); |
| 2513 | 2709 | ||
| @@ -2518,6 +2714,7 @@ trace_graph_create_with_callbacks(struct tracecmd_input *handle, | |||
| 2518 | colorAB.blue = 0; | 2714 | colorAB.blue = 0; |
| 2519 | 2715 | ||
| 2520 | eventbox = gtk_event_box_new(); | 2716 | eventbox = gtk_event_box_new(); |
| 2717 | set_label_b(eventbox); | ||
| 2521 | gtk_widget_show(eventbox); | 2718 | gtk_widget_show(eventbox); |
| 2522 | gtk_widget_modify_bg(eventbox, GTK_STATE_NORMAL, &colorAB); | 2719 | gtk_widget_modify_bg(eventbox, GTK_STATE_NORMAL, &colorAB); |
| 2523 | gtk_container_add(GTK_CONTAINER(eventbox), label); | 2720 | gtk_container_add(GTK_CONTAINER(eventbox), label); |
| @@ -2530,6 +2727,7 @@ trace_graph_create_with_callbacks(struct tracecmd_input *handle, | |||
| 2530 | 2727 | ||
| 2531 | ginfo->markb_label = gtk_label_new("0.0"); | 2728 | ginfo->markb_label = gtk_label_new("0.0"); |
| 2532 | eventbox = gtk_event_box_new(); | 2729 | eventbox = gtk_event_box_new(); |
| 2730 | set_label_b(eventbox); | ||
| 2533 | gtk_widget_show(eventbox); | 2731 | gtk_widget_show(eventbox); |
| 2534 | gtk_widget_modify_bg(eventbox, GTK_STATE_NORMAL, &color); | 2732 | gtk_widget_modify_bg(eventbox, GTK_STATE_NORMAL, &color); |
| 2535 | gtk_container_add(GTK_CONTAINER(eventbox), ginfo->markb_label); | 2733 | gtk_container_add(GTK_CONTAINER(eventbox), ginfo->markb_label); |
diff --git a/trace-graph.h b/trace-graph.h index 91ae161..15ad4b2 100644 --- a/trace-graph.h +++ b/trace-graph.h | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <gtk/gtk.h> | 24 | #include <gtk/gtk.h> |
| 25 | #include "trace-cmd.h" | 25 | #include "trace-cmd.h" |
| 26 | #include "trace-hash.h" | 26 | #include "trace-hash.h" |
| 27 | #include "trace-xml.h" | ||
| 27 | 28 | ||
| 28 | struct graph_info; | 29 | struct graph_info; |
| 29 | 30 | ||
| @@ -306,6 +307,15 @@ void trace_graph_copy_filter(struct graph_info *ginfo, | |||
| 306 | struct event_filter *event_filter); | 307 | struct event_filter *event_filter); |
| 307 | gint *trace_graph_task_list(struct graph_info *ginfo); | 308 | gint *trace_graph_task_list(struct graph_info *ginfo); |
| 308 | 309 | ||
| 310 | int trace_graph_load_filters(struct graph_info *ginfo, | ||
| 311 | struct tracecmd_xml_handle *handle); | ||
| 312 | int trace_graph_save_filters(struct graph_info *ginfo, | ||
| 313 | struct tracecmd_xml_handle *handle); | ||
| 314 | void trace_graph_update_filters(struct graph_info *ginfo, | ||
| 315 | struct filter_task *task_filter, | ||
| 316 | struct filter_task *hide_tasks); | ||
| 317 | void trace_graph_refresh_filters(struct graph_info *ginfo); | ||
| 318 | |||
| 309 | /* plots */ | 319 | /* plots */ |
| 310 | void trace_graph_plot_free(struct graph_info *ginfo); | 320 | void trace_graph_plot_free(struct graph_info *ginfo); |
| 311 | void trace_graph_plot_init(struct graph_info *ginfo); | 321 | void trace_graph_plot_init(struct graph_info *ginfo); |
diff --git a/trace-gui.h b/trace-gui.h new file mode 100644 index 0000000..a2d261f --- /dev/null +++ b/trace-gui.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; version 2 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | * | ||
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 20 | */ | ||
| 21 | #ifndef _TRACE_GUI | ||
| 22 | #define _TRACE_GUI | ||
| 23 | |||
| 24 | #include <gtk/gtk.h> | ||
| 25 | |||
| 26 | enum trace_dialog_type { | ||
| 27 | TRACE_GUI_INFO, | ||
| 28 | TRACE_GUI_WARNING, | ||
| 29 | TRACE_GUI_ERROR, | ||
| 30 | }; | ||
| 31 | |||
| 32 | GtkWidget *trace_status_bar_new(void); | ||
| 33 | |||
| 34 | void trace_dialog_register_window(GtkWidget *window); | ||
| 35 | |||
| 36 | void trace_show_help(GtkWidget *window, const gchar *link, GError **error); | ||
| 37 | |||
| 38 | void trace_dialog(GtkWindow *parent, enum trace_dialog_type type, | ||
| 39 | gchar *message, ...); | ||
| 40 | |||
| 41 | gchar *trace_get_file_dialog(const gchar *title); | ||
| 42 | |||
| 43 | |||
| 44 | #endif /* _TRACE_GUI */ | ||
diff --git a/trace-hash.c b/trace-hash.c index 1197913..ed53ee1 100644 --- a/trace-hash.c +++ b/trace-hash.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 20 | */ | 20 | */ |
| 21 | #include <stdio.h> | 21 | #include <stdio.h> |
| 22 | #include <stdlib.h> | ||
| 22 | #include <string.h> | 23 | #include <string.h> |
| 23 | #include <stdarg.h> | 24 | #include <stdarg.h> |
| 24 | 25 | ||
| @@ -155,3 +156,65 @@ struct filter_task *filter_task_hash_copy(struct filter_task *hash) | |||
| 155 | 156 | ||
| 156 | return new_hash; | 157 | return new_hash; |
| 157 | } | 158 | } |
| 159 | |||
| 160 | int *filter_task_pids(struct filter_task *hash) | ||
| 161 | { | ||
| 162 | struct filter_task_item *task; | ||
| 163 | int *pids; | ||
| 164 | int count = 0; | ||
| 165 | int i; | ||
| 166 | |||
| 167 | if (!hash->count) | ||
| 168 | return NULL; | ||
| 169 | |||
| 170 | pids = malloc(sizeof(*pids) * (hash->count + 1)); | ||
| 171 | if (!pids) | ||
| 172 | return NULL; | ||
| 173 | |||
| 174 | for (i = 0; i < FILTER_TASK_HASH_SIZE; i++) { | ||
| 175 | task = hash->hash[i]; | ||
| 176 | while (task) { | ||
| 177 | pids[count++] = task->pid; | ||
| 178 | task = task->next; | ||
| 179 | } | ||
| 180 | } | ||
| 181 | pids[count] = -1; | ||
| 182 | |||
| 183 | return pids; | ||
| 184 | } | ||
| 185 | |||
| 186 | /** | ||
| 187 | * filter_task_compare - compare two task hashs to see if they are equal | ||
| 188 | * @hash1: one hash to compare | ||
| 189 | * @hash2: another hash to compare to @hash1 | ||
| 190 | * | ||
| 191 | * Returns 1 if the two hashes are the same, 0 otherwise. | ||
| 192 | */ | ||
| 193 | int filter_task_compare(struct filter_task *hash1, struct filter_task *hash2) | ||
| 194 | { | ||
| 195 | int *pids; | ||
| 196 | int ret = 0; | ||
| 197 | int i; | ||
| 198 | |||
| 199 | /* If counts don't match, then they obviously are not the same */ | ||
| 200 | if (hash1->count != hash2->count) | ||
| 201 | return 0; | ||
| 202 | |||
| 203 | /* If both hashes are empty, they are the same */ | ||
| 204 | if (!hash1->count && !hash2->count) | ||
| 205 | return 1; | ||
| 206 | |||
| 207 | /* Now compare the pids of one hash with the other */ | ||
| 208 | pids = filter_task_pids(hash1); | ||
| 209 | for (i = 0; pids[i] >= 0; i++) { | ||
| 210 | if (!filter_task_find_pid(hash2, pids[i])) | ||
| 211 | break; | ||
| 212 | } | ||
| 213 | |||
| 214 | if (pids[i] == -1) | ||
| 215 | ret = 1; | ||
| 216 | |||
| 217 | free(pids); | ||
| 218 | |||
| 219 | return ret; | ||
| 220 | } | ||
diff --git a/trace-hash.h b/trace-hash.h index 1aaa828..b5296eb 100644 --- a/trace-hash.h +++ b/trace-hash.h | |||
| @@ -42,6 +42,8 @@ void filter_task_clear(struct filter_task *hash); | |||
| 42 | struct filter_task *filter_task_hash_alloc(void); | 42 | struct filter_task *filter_task_hash_alloc(void); |
| 43 | void filter_task_hash_free(struct filter_task *hash); | 43 | void filter_task_hash_free(struct filter_task *hash); |
| 44 | struct filter_task *filter_task_hash_copy(struct filter_task *hash); | 44 | struct filter_task *filter_task_hash_copy(struct filter_task *hash); |
| 45 | int *filter_task_pids(struct filter_task *hash); | ||
| 46 | int filter_task_compare(struct filter_task *hash1, struct filter_task *hash2); | ||
| 45 | 47 | ||
| 46 | static inline gint filter_task_count(struct filter_task *hash) | 48 | static inline gint filter_task_count(struct filter_task *hash) |
| 47 | { | 49 | { |
diff --git a/trace-util.c b/trace-util.c index 6605f1f..b8b6faf 100644 --- a/trace-util.c +++ b/trace-util.c | |||
| @@ -38,8 +38,6 @@ | |||
| 38 | int tracecmd_disable_sys_plugins; | 38 | int tracecmd_disable_sys_plugins; |
| 39 | int tracecmd_disable_plugins; | 39 | int tracecmd_disable_plugins; |
| 40 | 40 | ||
| 41 | #define __weak __attribute__((weak)) | ||
| 42 | |||
| 43 | #define _STR(x) #x | 41 | #define _STR(x) #x |
| 44 | #define STR(x) _STR(x) | 42 | #define STR(x) _STR(x) |
| 45 | 43 | ||
| @@ -53,71 +51,6 @@ struct plugin_list { | |||
| 53 | void *handle; | 51 | void *handle; |
| 54 | }; | 52 | }; |
| 55 | 53 | ||
| 56 | void __weak die(char *fmt, ...) | ||
| 57 | { | ||
| 58 | va_list ap; | ||
| 59 | int ret = errno; | ||
| 60 | |||
| 61 | if (errno) | ||
| 62 | perror("trace-cmd"); | ||
| 63 | else | ||
| 64 | ret = -1; | ||
| 65 | |||
| 66 | va_start(ap, fmt); | ||
| 67 | fprintf(stderr, " "); | ||
| 68 | vfprintf(stderr, fmt, ap); | ||
| 69 | va_end(ap); | ||
| 70 | |||
| 71 | fprintf(stderr, "\n"); | ||
| 72 | exit(ret); | ||
| 73 | } | ||
| 74 | |||
| 75 | void __weak warning(char *fmt, ...) | ||
| 76 | { | ||
| 77 | va_list ap; | ||
| 78 | |||
| 79 | if (errno) | ||
| 80 | perror("trace-cmd"); | ||
| 81 | errno = 0; | ||
| 82 | |||
| 83 | va_start(ap, fmt); | ||
| 84 | fprintf(stderr, " "); | ||
| 85 | vfprintf(stderr, fmt, ap); | ||
| 86 | va_end(ap); | ||
| 87 | |||
| 88 | fprintf(stderr, "\n"); | ||
| 89 | } | ||
| 90 | |||
| 91 | void __weak pr_stat(char *fmt, ...) | ||
| 92 | { | ||
| 93 | va_list ap; | ||
| 94 | |||
| 95 | va_start(ap, fmt); | ||
| 96 | vprintf(fmt, ap); | ||
| 97 | va_end(ap); | ||
| 98 | |||
| 99 | printf("\n"); | ||
| 100 | } | ||
| 101 | |||
| 102 | void __weak *malloc_or_die(unsigned int size) | ||
| 103 | { | ||
| 104 | void *data; | ||
| 105 | |||
| 106 | data = malloc(size); | ||
| 107 | if (!data) | ||
| 108 | die("malloc"); | ||
| 109 | return data; | ||
| 110 | } | ||
| 111 | |||
| 112 | int __weak bigendian(void) | ||
| 113 | { | ||
| 114 | unsigned char str[] = { 0x1, 0x2, 0x3, 0x4 }; | ||
| 115 | unsigned int *ptr; | ||
| 116 | |||
| 117 | ptr = (unsigned int *)str; | ||
| 118 | return *ptr == 0x01020304; | ||
| 119 | } | ||
| 120 | |||
| 121 | void parse_cmdlines(struct pevent *pevent, | 54 | void parse_cmdlines(struct pevent *pevent, |
| 122 | char *file, int size __unused) | 55 | char *file, int size __unused) |
| 123 | { | 56 | { |
diff --git a/trace-view-main.c b/trace-view-main.c index 52678ce..59d6838 100644 --- a/trace-view-main.c +++ b/trace-view-main.c | |||
| @@ -28,6 +28,12 @@ | |||
| 28 | 28 | ||
| 29 | #include "trace-cmd.h" | 29 | #include "trace-cmd.h" |
| 30 | #include "trace-view.h" | 30 | #include "trace-view.h" |
| 31 | #include "trace-xml.h" | ||
| 32 | #include "trace-filter.h" | ||
| 33 | #include "trace-gui.h" | ||
| 34 | #include "trace-compat.h" | ||
| 35 | |||
| 36 | #include "version.h" | ||
| 31 | 37 | ||
| 32 | #define version "0.1.1" | 38 | #define version "0.1.1" |
| 33 | 39 | ||
| @@ -38,8 +44,13 @@ | |||
| 38 | static char *input_file; | 44 | static char *input_file; |
| 39 | 45 | ||
| 40 | struct trace_tree_info { | 46 | struct trace_tree_info { |
| 41 | GtkWidget *trace_tree; | 47 | struct tracecmd_input *handle; |
| 42 | GtkWidget *spin; | 48 | GtkWidget *trace_tree; |
| 49 | GtkWidget *spin; | ||
| 50 | gint filter_enabled; | ||
| 51 | gint filter_task_selected; | ||
| 52 | struct filter_task *task_filter; | ||
| 53 | struct filter_task *hide_tasks; | ||
| 43 | }; | 54 | }; |
| 44 | 55 | ||
| 45 | void usage(char *prog) | 56 | void usage(char *prog) |
| @@ -55,26 +66,76 @@ load_clicked (gpointer data) | |||
| 55 | { | 66 | { |
| 56 | struct trace_tree_info *info = data; | 67 | struct trace_tree_info *info = data; |
| 57 | struct tracecmd_input *handle; | 68 | struct tracecmd_input *handle; |
| 58 | GtkWidget *dialog; | ||
| 59 | gchar *filename; | 69 | gchar *filename; |
| 60 | 70 | ||
| 61 | dialog = gtk_file_chooser_dialog_new("Load File", | 71 | filename = trace_get_file_dialog("Load File"); |
| 62 | NULL, | 72 | if (!filename) |
| 63 | GTK_FILE_CHOOSER_ACTION_OPEN, | 73 | return; |
| 64 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | 74 | |
| 65 | GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, | 75 | handle = tracecmd_open(filename); |
| 66 | NULL); | 76 | if (handle) { |
| 67 | if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { | 77 | trace_view_reload(info->trace_tree, handle, info->spin); |
| 68 | filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); | 78 | /* Free handle when freeing the trace tree */ |
| 69 | handle = tracecmd_open(filename); | 79 | tracecmd_close(handle); |
| 70 | if (handle) { | 80 | info->handle = handle; |
| 71 | trace_view_reload(info->trace_tree, handle, info->spin); | ||
| 72 | /* Free handle when freeing the trace tree */ | ||
| 73 | tracecmd_close(handle); | ||
| 74 | } | ||
| 75 | g_free(filename); | ||
| 76 | } | 81 | } |
| 77 | gtk_widget_destroy(dialog); | 82 | g_free(filename); |
| 83 | } | ||
| 84 | |||
| 85 | /* Callback for the clicked signal of the Load Filters button */ | ||
| 86 | static void | ||
| 87 | load_filters_clicked (gpointer data) | ||
| 88 | { | ||
| 89 | struct trace_tree_info *info = data; | ||
| 90 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->trace_tree); | ||
| 91 | struct tracecmd_xml_handle *handle; | ||
| 92 | gchar *filename; | ||
| 93 | |||
| 94 | filename = trace_get_file_dialog("Load Filters"); | ||
| 95 | if (!filename) | ||
| 96 | return; | ||
| 97 | |||
| 98 | handle = tracecmd_xml_open(filename); | ||
| 99 | if (!handle) { | ||
| 100 | warning("Could not open %s", filename); | ||
| 101 | return; | ||
| 102 | } | ||
| 103 | g_free(filename); | ||
| 104 | |||
| 105 | trace_filter_load_filters(handle, | ||
| 106 | "ListTaskFilter", | ||
| 107 | info->task_filter, | ||
| 108 | info->hide_tasks); | ||
| 109 | |||
| 110 | trace_view_load_filters(handle, trace_tree); | ||
| 111 | |||
| 112 | tracecmd_xml_close(handle); | ||
| 113 | } | ||
| 114 | |||
| 115 | /* Callback for the clicked signal of the Save Filters button */ | ||
| 116 | static void | ||
| 117 | save_filters_clicked (gpointer data) | ||
| 118 | { | ||
| 119 | struct trace_tree_info *info = data; | ||
| 120 | GtkTreeView *trace_tree = GTK_TREE_VIEW(info->trace_tree); | ||
| 121 | struct tracecmd_xml_handle *handle; | ||
| 122 | gchar *filename; | ||
| 123 | |||
| 124 | filename = trace_get_file_dialog("Save Filters"); | ||
| 125 | if (!filename) | ||
| 126 | return; | ||
| 127 | |||
| 128 | handle = tracecmd_xml_create(filename, VERSION_STRING); | ||
| 129 | if (!handle) | ||
| 130 | warning("Could not create %s", filename); | ||
| 131 | g_free(filename); | ||
| 132 | |||
| 133 | trace_filter_save_filters(handle, | ||
| 134 | "ListTaskFilter", | ||
| 135 | info->task_filter, info->hide_tasks); | ||
| 136 | trace_view_save_filters(handle, trace_tree); | ||
| 137 | |||
| 138 | tracecmd_xml_close(handle); | ||
| 78 | } | 139 | } |
| 79 | 140 | ||
| 80 | /* Callback for the clicked signal of the Exit button */ | 141 | /* Callback for the clicked signal of the Exit button */ |
| @@ -162,24 +223,209 @@ cpus_clicked (gpointer data) | |||
| 162 | trace_view_cpu_filter_callback, trace_tree); | 223 | trace_view_cpu_filter_callback, trace_tree); |
| 163 | } | 224 | } |
| 164 | 225 | ||
| 165 | #if 0 | 226 | static void |
| 166 | static GtkTreeModel * | 227 | filter_list_clicked (gpointer data) |
| 167 | create_combo_box_model(void) | ||
| 168 | { | 228 | { |
| 169 | GtkListStore *store; | 229 | struct trace_tree_info *info = data; |
| 170 | GtkTreeIter iter; | 230 | |
| 231 | if (!filter_task_count(info->task_filter) && | ||
| 232 | !filter_task_count(info->hide_tasks)) | ||
| 233 | return; | ||
| 234 | |||
| 235 | info->filter_enabled ^= 1; | ||
| 236 | |||
| 237 | if (info->filter_enabled) | ||
| 238 | trace_view_update_filters(info->trace_tree, | ||
| 239 | info->task_filter, | ||
| 240 | info->hide_tasks); | ||
| 241 | else | ||
| 242 | trace_view_update_filters(info->trace_tree, NULL, NULL); | ||
| 243 | } | ||
| 244 | |||
| 245 | static void update_task_filter(struct trace_tree_info *info, | ||
| 246 | struct filter_task *filter) | ||
| 247 | { | ||
| 248 | struct filter_task_item *task; | ||
| 249 | gint pid = info->filter_task_selected; | ||
| 250 | |||
| 251 | task = filter_task_find_pid(filter, pid); | ||
| 252 | |||
| 253 | if (task) | ||
| 254 | filter_task_remove_pid(filter, pid); | ||
| 255 | else | ||
| 256 | filter_task_add_pid(filter, pid); | ||
| 257 | |||
| 258 | if (info->filter_enabled) | ||
| 259 | trace_view_update_filters(info->trace_tree, | ||
| 260 | info->task_filter, | ||
| 261 | info->hide_tasks); | ||
| 262 | } | ||
| 263 | |||
| 264 | static void filter_add_task_clicked(gpointer data) | ||
| 265 | { | ||
| 266 | struct trace_tree_info *info = data; | ||
| 267 | |||
| 268 | update_task_filter(info, info->task_filter); | ||
| 269 | } | ||
| 270 | |||
| 271 | static void filter_hide_task_clicked(gpointer data) | ||
| 272 | { | ||
| 273 | struct trace_tree_info *info = data; | ||
| 274 | |||
| 275 | update_task_filter(info, info->hide_tasks); | ||
| 276 | } | ||
| 277 | |||
| 278 | static void | ||
| 279 | filter_clear_tasks_clicked (gpointer data) | ||
| 280 | { | ||
| 281 | struct trace_tree_info *info = data; | ||
| 282 | |||
| 283 | trace_view_update_filters(info->trace_tree, NULL, NULL); | ||
| 284 | info->filter_enabled = 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | static gboolean | ||
| 288 | do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | ||
| 289 | { | ||
| 290 | struct trace_tree_info *info = data; | ||
| 291 | static GtkWidget *menu; | ||
| 292 | static GtkWidget *menu_filter_enable; | ||
| 293 | static GtkWidget *menu_filter_add_task; | ||
| 294 | static GtkWidget *menu_filter_hide_task; | ||
| 295 | static GtkWidget *menu_filter_clear_tasks; | ||
| 296 | struct pevent *pevent; | ||
| 297 | struct record *record; | ||
| 298 | TraceViewRecord *vrec; | ||
| 299 | GtkTreeModel *model; | ||
| 300 | const char *comm; | ||
| 301 | gchar *text; | ||
| 302 | gint pid; | ||
| 303 | gint len; | ||
| 304 | guint64 offset; | ||
| 305 | gint row; | ||
| 306 | gint cpu; | ||
| 307 | |||
| 308 | if (!menu) { | ||
| 309 | menu = gtk_menu_new(); | ||
| 310 | |||
| 311 | menu_filter_enable = gtk_menu_item_new_with_label("Enable Filter"); | ||
| 312 | gtk_widget_show(menu_filter_enable); | ||
| 313 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_enable); | ||
| 314 | |||
| 315 | g_signal_connect_swapped (G_OBJECT (menu_filter_enable), "activate", | ||
| 316 | G_CALLBACK (filter_list_clicked), | ||
| 317 | data); | ||
| 318 | |||
| 319 | menu_filter_add_task = gtk_menu_item_new_with_label("Add Task"); | ||
| 320 | gtk_widget_show(menu_filter_add_task); | ||
| 321 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_add_task); | ||
| 322 | |||
| 323 | g_signal_connect_swapped (G_OBJECT (menu_filter_add_task), "activate", | ||
| 324 | G_CALLBACK (filter_add_task_clicked), | ||
| 325 | data); | ||
| 326 | |||
| 327 | menu_filter_hide_task = gtk_menu_item_new_with_label("Hide Task"); | ||
| 328 | gtk_widget_show(menu_filter_hide_task); | ||
| 329 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_hide_task); | ||
| 330 | |||
| 331 | g_signal_connect_swapped (G_OBJECT (menu_filter_hide_task), "activate", | ||
| 332 | G_CALLBACK (filter_hide_task_clicked), | ||
| 333 | data); | ||
| 334 | |||
| 335 | menu_filter_clear_tasks = gtk_menu_item_new_with_label("Clear Task Filter"); | ||
| 336 | gtk_widget_show(menu_filter_clear_tasks); | ||
| 337 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_clear_tasks); | ||
| 338 | |||
| 339 | g_signal_connect_swapped (G_OBJECT (menu_filter_clear_tasks), "activate", | ||
| 340 | G_CALLBACK (filter_clear_tasks_clicked), | ||
| 341 | data); | ||
| 342 | |||
| 343 | } | ||
| 344 | |||
| 345 | row = trace_view_get_selected_row(GTK_WIDGET(info->trace_tree)); | ||
| 346 | if (row >= 0) { | ||
| 347 | |||
| 348 | model = gtk_tree_view_get_model(GTK_TREE_VIEW(info->trace_tree)); | ||
| 349 | vrec = trace_view_store_get_row(TRACE_VIEW_STORE(model), row); | ||
| 350 | offset = vrec->offset; | ||
| 351 | |||
| 352 | record = tracecmd_read_at(info->handle, offset, &cpu); | ||
| 353 | |||
| 354 | if (record) { | ||
| 355 | pevent = tracecmd_get_pevent(info->handle); | ||
| 356 | pid = pevent_data_pid(pevent, record); | ||
| 357 | comm = pevent_data_comm_from_pid(pevent, pid); | ||
| 358 | |||
| 359 | len = strlen(comm) + 50; | ||
| 360 | |||
| 361 | text = g_malloc(len); | ||
| 362 | g_assert(text); | ||
| 363 | |||
| 364 | if (filter_task_find_pid(info->task_filter, pid)) | ||
| 365 | snprintf(text, len, "Remove %s-%d from filter", comm, pid); | ||
| 366 | else | ||
| 367 | snprintf(text, len, "Add %s-%d to filter", comm, pid); | ||
| 368 | |||
| 369 | info->filter_task_selected = pid; | ||
| 370 | |||
| 371 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_add_task), | ||
| 372 | text); | ||
| 373 | |||
| 374 | if (filter_task_find_pid(info->hide_tasks, pid)) | ||
| 375 | snprintf(text, len, "Show %s-%d", comm, pid); | ||
| 376 | else | ||
| 377 | snprintf(text, len, "Hide %s-%d", comm, pid); | ||
| 378 | |||
| 379 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_hide_task), | ||
| 380 | text); | ||
| 381 | |||
| 382 | g_free(text); | ||
| 383 | |||
| 384 | info->filter_task_selected = pid; | ||
| 385 | |||
| 386 | gtk_widget_show(menu_filter_add_task); | ||
| 387 | gtk_widget_show(menu_filter_hide_task); | ||
| 388 | free_record(record); | ||
| 389 | } | ||
| 390 | } else { | ||
| 391 | gtk_widget_hide(menu_filter_add_task); | ||
| 392 | gtk_widget_hide(menu_filter_hide_task); | ||
| 393 | } | ||
| 394 | |||
| 395 | if (info->filter_enabled) | ||
| 396 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_enable), | ||
| 397 | "Disable List Filter"); | ||
| 398 | else | ||
| 399 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_enable), | ||
| 400 | "Enable List Filter"); | ||
| 401 | |||
| 402 | if (filter_task_count(info->task_filter) || | ||
| 403 | filter_task_count(info->hide_tasks)) { | ||
| 404 | gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE); | ||
| 405 | gtk_widget_set_sensitive(menu_filter_enable, TRUE); | ||
| 406 | } else { | ||
| 407 | gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE); | ||
| 408 | gtk_widget_set_sensitive(menu_filter_enable, FALSE); | ||
| 409 | } | ||
| 410 | |||
| 411 | gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, | ||
| 412 | gtk_get_current_event_time()); | ||
| 413 | |||
| 414 | return TRUE; | ||
| 415 | } | ||
| 171 | 416 | ||
| 172 | store = gtk_list_store_new(1, G_TYPE_STRING); | 417 | static gboolean |
| 173 | gtk_list_store_append(store, &iter); | 418 | button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) |
| 174 | gtk_list_store_set(store, &iter, 0, "1", -1); | 419 | { |
| 420 | if (event->button == 3) | ||
| 421 | return do_tree_popup(widget, event, data); | ||
| 175 | 422 | ||
| 176 | return GTK_TREE_MODEL(store); | 423 | return FALSE; |
| 177 | } | 424 | } |
| 178 | #endif | ||
| 179 | 425 | ||
| 180 | void trace_view(int argc, char **argv) | 426 | void trace_view(int argc, char **argv) |
| 181 | { | 427 | { |
| 182 | static struct tracecmd_input *handle; | 428 | static struct tracecmd_input *handle = NULL; |
| 183 | struct trace_tree_info tree_info; | 429 | struct trace_tree_info tree_info; |
| 184 | struct stat st; | 430 | struct stat st; |
| 185 | GtkWidget *trace_tree; | 431 | GtkWidget *trace_tree; |
| @@ -193,6 +439,7 @@ void trace_view(int argc, char **argv) | |||
| 193 | GtkWidget *scrollwin; | 439 | GtkWidget *scrollwin; |
| 194 | GtkWidget *label; | 440 | GtkWidget *label; |
| 195 | GtkWidget *spin; | 441 | GtkWidget *spin; |
| 442 | GtkWidget *statusbar; | ||
| 196 | int ret; | 443 | int ret; |
| 197 | int c; | 444 | int c; |
| 198 | 445 | ||
| @@ -227,10 +474,17 @@ void trace_view(int argc, char **argv) | |||
| 227 | if (input_file) | 474 | if (input_file) |
| 228 | handle = tracecmd_open(input_file); | 475 | handle = tracecmd_open(input_file); |
| 229 | 476 | ||
| 477 | memset(&tree_info, 0, sizeof(tree_info)); | ||
| 478 | tree_info.handle = handle; | ||
| 479 | tree_info.task_filter = filter_task_hash_alloc(); | ||
| 480 | tree_info.hide_tasks = filter_task_hash_alloc(); | ||
| 481 | |||
| 230 | /* --- Main window --- */ | 482 | /* --- Main window --- */ |
| 231 | 483 | ||
| 232 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | 484 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
| 233 | 485 | ||
| 486 | trace_dialog_register_window(window); | ||
| 487 | |||
| 234 | /* --- Top Level Vbox --- */ | 488 | /* --- Top Level Vbox --- */ |
| 235 | 489 | ||
| 236 | vbox = gtk_vbox_new(FALSE, 0); | 490 | vbox = gtk_vbox_new(FALSE, 0); |
| @@ -255,12 +509,11 @@ void trace_view(int argc, char **argv) | |||
| 255 | 509 | ||
| 256 | /* --- File - Load Option --- */ | 510 | /* --- File - Load Option --- */ |
| 257 | 511 | ||
| 258 | sub_item = gtk_menu_item_new_with_label("Load info"); | 512 | sub_item = gtk_menu_item_new_with_label("Load data"); |
| 259 | 513 | ||
| 260 | /* Add them to the menu */ | 514 | /* Add them to the menu */ |
| 261 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | 515 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); |
| 262 | 516 | ||
| 263 | /* We can attach the Quit menu item to our exit function */ | ||
| 264 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | 517 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", |
| 265 | G_CALLBACK (load_clicked), | 518 | G_CALLBACK (load_clicked), |
| 266 | (gpointer) &tree_info); | 519 | (gpointer) &tree_info); |
| @@ -269,6 +522,36 @@ void trace_view(int argc, char **argv) | |||
| 269 | gtk_widget_show(sub_item); | 522 | gtk_widget_show(sub_item); |
| 270 | 523 | ||
| 271 | 524 | ||
| 525 | /* --- File - Load Filter Option --- */ | ||
| 526 | |||
| 527 | sub_item = gtk_menu_item_new_with_label("Load filters"); | ||
| 528 | |||
| 529 | /* Add them to the menu */ | ||
| 530 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 531 | |||
| 532 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 533 | G_CALLBACK (load_filters_clicked), | ||
| 534 | (gpointer) &tree_info); | ||
| 535 | |||
| 536 | /* We do need to show menu items */ | ||
| 537 | gtk_widget_show(sub_item); | ||
| 538 | |||
| 539 | |||
| 540 | /* --- File - Save Filter Option --- */ | ||
| 541 | |||
| 542 | sub_item = gtk_menu_item_new_with_label("Save filters"); | ||
| 543 | |||
| 544 | /* Add them to the menu */ | ||
| 545 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
| 546 | |||
| 547 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
| 548 | G_CALLBACK (save_filters_clicked), | ||
| 549 | (gpointer) &tree_info); | ||
| 550 | |||
| 551 | /* We do need to show menu items */ | ||
| 552 | gtk_widget_show(sub_item); | ||
| 553 | |||
| 554 | |||
| 272 | /* --- File - Quit Option --- */ | 555 | /* --- File - Quit Option --- */ |
| 273 | 556 | ||
| 274 | sub_item = gtk_menu_item_new_with_label("Quit"); | 557 | sub_item = gtk_menu_item_new_with_label("Quit"); |
| @@ -385,6 +668,10 @@ void trace_view(int argc, char **argv) | |||
| 385 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | 668 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); |
| 386 | gtk_widget_show(label); | 669 | gtk_widget_show(label); |
| 387 | 670 | ||
| 671 | gtk_signal_connect(GTK_OBJECT(trace_tree), "button_press_event", | ||
| 672 | (GtkSignalFunc) button_press_event, | ||
| 673 | (gpointer) &tree_info); | ||
| 674 | |||
| 388 | trace_view_search_setup(GTK_BOX(hbox), GTK_TREE_VIEW(trace_tree)); | 675 | trace_view_search_setup(GTK_BOX(hbox), GTK_TREE_VIEW(trace_tree)); |
| 389 | 676 | ||
| 390 | /* --- Top Level Hbox --- */ | 677 | /* --- Top Level Hbox --- */ |
| @@ -407,6 +694,13 @@ void trace_view(int argc, char **argv) | |||
| 407 | gtk_widget_show(trace_tree); | 694 | gtk_widget_show(trace_tree); |
| 408 | 695 | ||
| 409 | 696 | ||
| 697 | /* --- Set up Status Bar --- */ | ||
| 698 | |||
| 699 | statusbar = trace_status_bar_new(); | ||
| 700 | |||
| 701 | gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); | ||
| 702 | gtk_widget_show(statusbar); | ||
| 703 | |||
| 410 | /********************************************** | 704 | /********************************************** |
| 411 | * Main Window | 705 | * Main Window |
| 412 | **********************************************/ | 706 | **********************************************/ |
diff --git a/trace-view-store.c b/trace-view-store.c index ba40aad..6f70ca5 100644 --- a/trace-view-store.c +++ b/trace-view-store.c | |||
| @@ -1330,7 +1330,6 @@ void trace_view_store_assign_filters(TraceViewStore *store, | |||
| 1330 | 1330 | ||
| 1331 | if (store->task_filter != task_filter) | 1331 | if (store->task_filter != task_filter) |
| 1332 | store->task_filter = filter_task_hash_copy(task_filter); | 1332 | store->task_filter = filter_task_hash_copy(task_filter); |
| 1333 | |||
| 1334 | } | 1333 | } |
| 1335 | 1334 | ||
| 1336 | 1335 | ||
diff --git a/trace-view.c b/trace-view.c index 59e7e1a..8d121d1 100644 --- a/trace-view.c +++ b/trace-view.c | |||
| @@ -870,3 +870,112 @@ void trace_view_search_setup(GtkBox *box, GtkTreeView *treeview) | |||
| 870 | G_CALLBACK (search_tree), | 870 | G_CALLBACK (search_tree), |
| 871 | (gpointer) info); | 871 | (gpointer) info); |
| 872 | } | 872 | } |
| 873 | |||
| 874 | int trace_view_save_filters(struct tracecmd_xml_handle *handle, | ||
| 875 | GtkTreeView *trace_tree) | ||
| 876 | { | ||
| 877 | struct event_filter *event_filter; | ||
| 878 | GtkTreeModel *model; | ||
| 879 | TraceViewStore *store; | ||
| 880 | gboolean all_events; | ||
| 881 | |||
| 882 | model = gtk_tree_view_get_model(trace_tree); | ||
| 883 | if (!model) | ||
| 884 | return -1; | ||
| 885 | |||
| 886 | store = TRACE_VIEW_STORE(model); | ||
| 887 | |||
| 888 | tracecmd_xml_start_system(handle, "TraceView"); | ||
| 889 | |||
| 890 | all_events = trace_view_store_get_all_events_enabled(store); | ||
| 891 | event_filter = trace_view_store_get_event_filter(store); | ||
| 892 | |||
| 893 | tracecmd_xml_start_sub_system(handle, "EventFilter"); | ||
| 894 | |||
| 895 | if (all_events || !event_filter) | ||
| 896 | tracecmd_xml_write_element(handle, "FilterType", "all events"); | ||
| 897 | else { | ||
| 898 | tracecmd_xml_write_element(handle, "FilterType", "filter"); | ||
| 899 | trace_filter_save_events(handle, event_filter); | ||
| 900 | } | ||
| 901 | |||
| 902 | tracecmd_xml_end_sub_system(handle); | ||
| 903 | |||
| 904 | tracecmd_xml_end_system(handle); | ||
| 905 | |||
| 906 | return 0; | ||
| 907 | } | ||
| 908 | |||
| 909 | static int load_event_filter(TraceViewStore *store, | ||
| 910 | struct tracecmd_xml_handle *handle, | ||
| 911 | struct tracecmd_xml_system_node *node) | ||
| 912 | { | ||
| 913 | struct tracecmd_xml_system_node *child; | ||
| 914 | struct event_filter *event_filter; | ||
| 915 | const char *name; | ||
| 916 | const char *value; | ||
| 917 | |||
| 918 | event_filter = trace_view_store_get_event_filter(store); | ||
| 919 | |||
| 920 | child = tracecmd_xml_node_child(node); | ||
| 921 | name = tracecmd_xml_node_type(child); | ||
| 922 | if (strcmp(name, "FilterType") != 0) | ||
| 923 | return -1; | ||
| 924 | |||
| 925 | value = tracecmd_xml_node_value(handle, child); | ||
| 926 | /* Do nothing with all events enabled */ | ||
| 927 | if (strcmp(value, "all events") == 0) | ||
| 928 | return 0; | ||
| 929 | |||
| 930 | node = tracecmd_xml_node_next(child); | ||
| 931 | if (!node) | ||
| 932 | return -1; | ||
| 933 | |||
| 934 | trace_view_store_clear_all_events_enabled(store); | ||
| 935 | |||
| 936 | trace_filter_load_events(event_filter, handle, node); | ||
| 937 | |||
| 938 | return 0; | ||
| 939 | } | ||
| 940 | |||
| 941 | int trace_view_load_filters(struct tracecmd_xml_handle *handle, | ||
| 942 | GtkTreeView *trace_tree) | ||
| 943 | { | ||
| 944 | struct tracecmd_xml_system *system; | ||
| 945 | struct tracecmd_xml_system_node *syschild; | ||
| 946 | GtkTreeModel *model; | ||
| 947 | TraceViewStore *store; | ||
| 948 | const char *name; | ||
| 949 | |||
| 950 | model = gtk_tree_view_get_model(trace_tree); | ||
| 951 | if (!model) | ||
| 952 | return -1; | ||
| 953 | |||
| 954 | store = TRACE_VIEW_STORE(model); | ||
| 955 | |||
| 956 | system = tracecmd_xml_find_system(handle, "TraceView"); | ||
| 957 | if (!system) | ||
| 958 | return -1; | ||
| 959 | |||
| 960 | syschild = tracecmd_xml_system_node(system); | ||
| 961 | if (!syschild) | ||
| 962 | goto out_free_sys; | ||
| 963 | |||
| 964 | do { | ||
| 965 | name = tracecmd_xml_node_type(syschild); | ||
| 966 | |||
| 967 | if (strcmp(name, "EventFilter") == 0) | ||
| 968 | load_event_filter(store, handle, syschild); | ||
| 969 | |||
| 970 | syschild = tracecmd_xml_node_next(syschild); | ||
| 971 | } while (syschild); | ||
| 972 | |||
| 973 | tracecmd_xml_free_system(system); | ||
| 974 | |||
| 975 | update_rows(trace_tree, store); | ||
| 976 | return 0; | ||
| 977 | |||
| 978 | out_free_sys: | ||
| 979 | tracecmd_xml_free_system(system); | ||
| 980 | return -1; | ||
| 981 | } | ||
diff --git a/trace-view.h b/trace-view.h index 182b285..81dac6f 100644 --- a/trace-view.h +++ b/trace-view.h | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | 23 | ||
| 24 | #include "trace-view-store.h" | 24 | #include "trace-view-store.h" |
| 25 | #include "trace-filter.h" | 25 | #include "trace-filter.h" |
| 26 | #include "trace-xml.h" | ||
| 26 | 27 | ||
| 27 | void | 28 | void |
| 28 | trace_view_load(GtkWidget *view, struct tracecmd_input *handle, | 29 | trace_view_load(GtkWidget *view, struct tracecmd_input *handle, |
| @@ -65,4 +66,9 @@ void trace_view_search_setup(GtkBox *box, GtkTreeView *treeview); | |||
| 65 | 66 | ||
| 66 | gint trace_view_get_selected_row(GtkWidget *treeview); | 67 | gint trace_view_get_selected_row(GtkWidget *treeview); |
| 67 | 68 | ||
| 69 | int trace_view_save_filters(struct tracecmd_xml_handle *handle, | ||
| 70 | GtkTreeView *treeview); | ||
| 71 | int trace_view_load_filters(struct tracecmd_xml_handle *handle, | ||
| 72 | GtkTreeView *treeview); | ||
| 73 | |||
| 68 | #endif /* _TRACE_VIEW_H */ | 74 | #endif /* _TRACE_VIEW_H */ |
diff --git a/trace-xml.c b/trace-xml.c new file mode 100644 index 0000000..bef1f9f --- /dev/null +++ b/trace-xml.c | |||
| @@ -0,0 +1,248 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | * | ||
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 20 | */ | ||
| 21 | #include <stdio.h> | ||
| 22 | #include <stdlib.h> | ||
| 23 | #include <stdarg.h> | ||
| 24 | #include <string.h> | ||
| 25 | |||
| 26 | #include <libxml/xmlwriter.h> | ||
| 27 | #include <libxml/parser.h> | ||
| 28 | #include <libxml/xpath.h> | ||
| 29 | |||
| 30 | #include "trace-cmd.h" | ||
| 31 | #include "trace-xml.h" | ||
| 32 | |||
| 33 | struct tracecmd_xml_handle { | ||
| 34 | xmlTextWriterPtr writer; | ||
| 35 | xmlDocPtr doc; | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct tracecmd_xml_system { | ||
| 39 | struct tracecmd_xml_handle *handle; | ||
| 40 | xmlXPathObjectPtr result; | ||
| 41 | xmlNodePtr cur; | ||
| 42 | }; | ||
| 43 | |||
| 44 | #define TRACE_ENCODING "UTF-8" | ||
| 45 | |||
| 46 | int tracecmd_xml_write_element(struct tracecmd_xml_handle *handle, | ||
| 47 | const char *obj, | ||
| 48 | const char *fmt, ...) | ||
| 49 | { | ||
| 50 | va_list ap; | ||
| 51 | int ret; | ||
| 52 | |||
| 53 | va_start(ap, fmt); | ||
| 54 | ret = xmlTextWriterWriteVFormatElement(handle->writer, | ||
| 55 | BAD_CAST obj, fmt, ap); | ||
| 56 | va_end(ap); | ||
| 57 | |||
| 58 | return ret; | ||
| 59 | } | ||
| 60 | |||
| 61 | struct tracecmd_xml_handle *tracecmd_xml_create(const char *name, | ||
| 62 | const char *version) | ||
| 63 | { | ||
| 64 | struct tracecmd_xml_handle *handle; | ||
| 65 | int ret; | ||
| 66 | |||
| 67 | handle = malloc_or_die(sizeof(*handle)); | ||
| 68 | memset(handle, 0, sizeof(*handle)); | ||
| 69 | |||
| 70 | handle->writer = xmlNewTextWriterFilename(name, 0); | ||
| 71 | if (!handle->writer) | ||
| 72 | goto fail_free; | ||
| 73 | |||
| 74 | ret = xmlTextWriterStartDocument(handle->writer, NULL, | ||
| 75 | TRACE_ENCODING, NULL); | ||
| 76 | if (ret < 0) | ||
| 77 | goto fail_close; | ||
| 78 | |||
| 79 | ret = xmlTextWriterStartElement(handle->writer, | ||
| 80 | BAD_CAST "KernelShark"); | ||
| 81 | if (ret < 0) | ||
| 82 | goto fail_close; | ||
| 83 | |||
| 84 | return handle; | ||
| 85 | |||
| 86 | fail_close: | ||
| 87 | xmlFreeTextWriter(handle->writer); | ||
| 88 | fail_free: | ||
| 89 | free(handle); | ||
| 90 | return NULL; | ||
| 91 | } | ||
| 92 | |||
| 93 | int tracecmd_xml_start_system(struct tracecmd_xml_handle *handle, | ||
| 94 | const char *system) | ||
| 95 | { | ||
| 96 | int ret; | ||
| 97 | |||
| 98 | ret = xmlTextWriterStartElement(handle->writer, | ||
| 99 | BAD_CAST system); | ||
| 100 | |||
| 101 | if (ret < 0) | ||
| 102 | return ret; | ||
| 103 | |||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | int tracecmd_xml_start_sub_system(struct tracecmd_xml_handle *handle, | ||
| 108 | const char *subsystem) | ||
| 109 | { | ||
| 110 | int ret; | ||
| 111 | |||
| 112 | ret = xmlTextWriterStartElement(handle->writer, | ||
| 113 | BAD_CAST subsystem); | ||
| 114 | |||
| 115 | return ret; | ||
| 116 | } | ||
| 117 | |||
| 118 | void tracecmd_xml_end_system(struct tracecmd_xml_handle *handle) | ||
| 119 | { | ||
| 120 | xmlTextWriterEndElement(handle->writer); | ||
| 121 | } | ||
| 122 | |||
| 123 | void tracecmd_xml_end_sub_system(struct tracecmd_xml_handle *handle) | ||
| 124 | { | ||
| 125 | xmlTextWriterEndElement(handle->writer); | ||
| 126 | } | ||
| 127 | |||
| 128 | void tracecmd_xml_close(struct tracecmd_xml_handle *handle) | ||
| 129 | { | ||
| 130 | if (handle->writer) { | ||
| 131 | xmlTextWriterEndElement(handle->writer); | ||
| 132 | xmlTextWriterEndDocument(handle->writer); | ||
| 133 | xmlFreeTextWriter(handle->writer); | ||
| 134 | } | ||
| 135 | if (handle->doc) { | ||
| 136 | xmlFreeDoc(handle->doc); | ||
| 137 | } | ||
| 138 | free(handle); | ||
| 139 | } | ||
| 140 | |||
| 141 | /***********************************************************/ | ||
| 142 | /*** Reading XML files ***/ | ||
| 143 | /***********************************************************/ | ||
| 144 | |||
| 145 | |||
| 146 | struct tracecmd_xml_handle *tracecmd_xml_open(const char *file) | ||
| 147 | { | ||
| 148 | struct tracecmd_xml_handle *handle; | ||
| 149 | |||
| 150 | handle = malloc_or_die(sizeof(*handle)); | ||
| 151 | memset(handle, 0, sizeof(*handle)); | ||
| 152 | |||
| 153 | handle->doc = xmlParseFile(file); | ||
| 154 | if (!handle->doc) | ||
| 155 | goto fail_free; | ||
| 156 | |||
| 157 | return handle; | ||
| 158 | |||
| 159 | fail_free: | ||
| 160 | free(handle); | ||
| 161 | return NULL; | ||
| 162 | } | ||
| 163 | |||
| 164 | struct tracecmd_xml_system * | ||
| 165 | tracecmd_xml_find_system(struct tracecmd_xml_handle *handle, | ||
| 166 | const char *system) | ||
| 167 | { | ||
| 168 | struct tracecmd_xml_system *sys; | ||
| 169 | xmlXPathContextPtr context; | ||
| 170 | xmlXPathObjectPtr result; | ||
| 171 | xmlChar *xpath; | ||
| 172 | char *path; | ||
| 173 | |||
| 174 | path = malloc_or_die(strlen(system) + 3); | ||
| 175 | sprintf(path, "//%s", system); | ||
| 176 | xpath = BAD_CAST path; | ||
| 177 | |||
| 178 | context = xmlXPathNewContext(handle->doc); | ||
| 179 | result = xmlXPathEvalExpression(xpath, context); | ||
| 180 | free(path); | ||
| 181 | |||
| 182 | if (xmlXPathNodeSetIsEmpty(result->nodesetval)) { | ||
| 183 | xmlXPathFreeObject(result); | ||
| 184 | return NULL; | ||
| 185 | } | ||
| 186 | |||
| 187 | sys = malloc_or_die(sizeof(*sys)); | ||
| 188 | sys->handle = handle; | ||
| 189 | sys->result = result; | ||
| 190 | sys->cur = result->nodesetval->nodeTab[0]->xmlChildrenNode; | ||
| 191 | |||
| 192 | return sys; | ||
| 193 | } | ||
| 194 | |||
| 195 | struct tracecmd_xml_system_node * | ||
| 196 | tracecmd_xml_system_node(struct tracecmd_xml_system *system) | ||
| 197 | { | ||
| 198 | return (struct tracecmd_xml_system_node *)system->cur; | ||
| 199 | } | ||
| 200 | |||
| 201 | const char *tracecmd_xml_node_type(struct tracecmd_xml_system_node *tnode) | ||
| 202 | { | ||
| 203 | xmlNodePtr node = (xmlNodePtr)tnode; | ||
| 204 | return (const char *)node->name; | ||
| 205 | } | ||
| 206 | |||
| 207 | struct tracecmd_xml_system_node * | ||
| 208 | tracecmd_xml_node_child(struct tracecmd_xml_system_node *tnode) | ||
| 209 | { | ||
| 210 | xmlNodePtr node = (xmlNodePtr)tnode; | ||
| 211 | return (struct tracecmd_xml_system_node *)node->xmlChildrenNode; | ||
| 212 | } | ||
| 213 | |||
| 214 | struct tracecmd_xml_system_node * | ||
| 215 | tracecmd_xml_node_next(struct tracecmd_xml_system_node *tnode) | ||
| 216 | { | ||
| 217 | xmlNodePtr node = (xmlNodePtr)tnode; | ||
| 218 | return (struct tracecmd_xml_system_node *)node->next; | ||
| 219 | } | ||
| 220 | |||
| 221 | const char *tracecmd_xml_node_value(struct tracecmd_xml_handle *handle, | ||
| 222 | struct tracecmd_xml_system_node *tnode) | ||
| 223 | { | ||
| 224 | xmlNodePtr node = (xmlNodePtr)tnode; | ||
| 225 | return (const char *)xmlNodeListGetString(handle->doc, node->xmlChildrenNode, 1); | ||
| 226 | } | ||
| 227 | |||
| 228 | void tracecmd_xml_free_system(struct tracecmd_xml_system *system) | ||
| 229 | { | ||
| 230 | xmlXPathFreeObject(system->result); | ||
| 231 | free(system); | ||
| 232 | } | ||
| 233 | |||
| 234 | int tracecmd_xml_system_exists(struct tracecmd_xml_handle *handle, | ||
| 235 | const char *system) | ||
| 236 | { | ||
| 237 | struct tracecmd_xml_system *sys; | ||
| 238 | int exists = 0; | ||
| 239 | |||
| 240 | sys = tracecmd_xml_find_system(handle, system); | ||
| 241 | if (sys) { | ||
| 242 | exists = 1; | ||
| 243 | tracecmd_xml_free_system(sys); | ||
| 244 | } | ||
| 245 | |||
| 246 | return exists; | ||
| 247 | } | ||
| 248 | |||
diff --git a/trace-xml.h b/trace-xml.h new file mode 100644 index 0000000..d1f62b0 --- /dev/null +++ b/trace-xml.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU Lesser General Public | ||
| 7 | * License as published by the Free Software Foundation; | ||
| 8 | * version 2.1 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU Lesser General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU Lesser General Public | ||
| 16 | * License along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | * | ||
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 20 | */ | ||
| 21 | #ifndef __TRACE_XML_H | ||
| 22 | #define __TRACE_XML_H | ||
| 23 | |||
| 24 | struct tracecmd_xml_handle; | ||
| 25 | struct tacecmd_xml_system; | ||
| 26 | struct tacecmd_xml_system_node; | ||
| 27 | |||
| 28 | struct tracecmd_xml_handle *tracecmd_xml_create(const char *name, const char *version); | ||
| 29 | struct tracecmd_xml_handle *tracecmd_xml_open(const char *name); | ||
| 30 | void tracecmd_xml_close(struct tracecmd_xml_handle *handle); | ||
| 31 | |||
| 32 | int tracecmd_xml_start_system(struct tracecmd_xml_handle *handle, | ||
| 33 | const char *system); | ||
| 34 | void tracecmd_xml_end_system(struct tracecmd_xml_handle *handle); | ||
| 35 | |||
| 36 | int tracecmd_xml_start_sub_system(struct tracecmd_xml_handle *handle, | ||
| 37 | const char *subsystem); | ||
| 38 | void tracecmd_xml_end_sub_system(struct tracecmd_xml_handle *handle); | ||
| 39 | |||
| 40 | int tracecmd_xml_write_element(struct tracecmd_xml_handle *handle, | ||
| 41 | const char *obj, | ||
| 42 | const char *fmt, ...); | ||
| 43 | |||
| 44 | struct tracecmd_xml_handle *tracecmd_xml_open(const char *file); | ||
| 45 | |||
| 46 | struct tracecmd_xml_system * | ||
| 47 | tracecmd_xml_find_system(struct tracecmd_xml_handle *handle, | ||
| 48 | const char *system); | ||
| 49 | void tracecmd_xml_free_system(struct tracecmd_xml_system *system); | ||
| 50 | struct tracecmd_xml_system_node * | ||
| 51 | tracecmd_xml_system_node(struct tracecmd_xml_system *system); | ||
| 52 | const char *tracecmd_xml_node_type(struct tracecmd_xml_system_node *tnode); | ||
| 53 | struct tracecmd_xml_system_node * | ||
| 54 | tracecmd_xml_node_child(struct tracecmd_xml_system_node *tnode); | ||
| 55 | struct tracecmd_xml_system_node * | ||
| 56 | tracecmd_xml_node_next(struct tracecmd_xml_system_node *tnode); | ||
| 57 | const char *tracecmd_xml_node_value(struct tracecmd_xml_handle *handle, | ||
| 58 | struct tracecmd_xml_system_node *tnode); | ||
| 59 | int tracecmd_xml_system_exists(struct tracecmd_xml_handle *handle, | ||
| 60 | const char *system); | ||
| 61 | |||
| 62 | #endif /* __TRACE_XML_H */ | ||
