aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-06-10 17:53:51 -0400
committerSteven Rostedt <rostedt@goodmis.org>2010-06-10 17:53:51 -0400
commit3c95290d3fb593145b8ce1163d795a08f05e112c (patch)
treee6fc1bea660993e4eaaf5b716bef577d6fbf692e
parentd01b699fffc573e7653e00d608444735c04f9dca (diff)
parentb09e5f4f3fc5c8fc2c51376050af19660c8053f4 (diff)
Merge branch 'kernelshark-devel' into trace-cmd
Conflicts: Makefile Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Documentation/HTML/images/kshark-cursor-1.pngbin0 -> 61110 bytes
-rw-r--r--Documentation/HTML/images/kshark-filter-advance-1.pngbin0 -> 21625 bytes
-rw-r--r--Documentation/HTML/images/kshark-filter-del-adv.pngbin0 -> 21730 bytes
-rw-r--r--Documentation/HTML/images/kshark-filter-event-adv-list.pngbin0 -> 20674 bytes
-rw-r--r--Documentation/HTML/images/kshark-filter-events-sched.pngbin0 -> 19572 bytes
-rw-r--r--Documentation/HTML/images/kshark-filter-events.pngbin0 -> 20090 bytes
-rw-r--r--Documentation/HTML/images/kshark-filter-list-adv-irq.pngbin0 -> 20789 bytes
-rw-r--r--Documentation/HTML/images/kshark-filter-sync-graph-1.pngbin0 -> 71003 bytes
-rw-r--r--Documentation/HTML/images/kshark-filter-task-menu.pngbin0 -> 83758 bytes
-rw-r--r--Documentation/HTML/images/kshark-filter.pngbin0 -> 64849 bytes
-rw-r--r--Documentation/HTML/images/kshark-graph-info-line.pngbin0 -> 2476 bytes
-rw-r--r--Documentation/HTML/images/kshark-graph-plot-area.pngbin0 -> 5210 bytes
-rw-r--r--Documentation/HTML/images/kshark-graph-plot-title.pngbin0 -> 1144 bytes
-rw-r--r--Documentation/HTML/images/kshark-list-adjust.pngbin0 -> 80113 bytes
-rw-r--r--Documentation/HTML/images/kshark-list-enable-filter-1.pngbin0 -> 83642 bytes
-rw-r--r--Documentation/HTML/images/kshark-list-graph-follow-1.pngbin0 -> 82268 bytes
-rw-r--r--Documentation/HTML/images/kshark-list-graph-follow-2.pngbin0 -> 81639 bytes
-rw-r--r--Documentation/HTML/images/kshark-list-info-area.pngbin0 -> 5083 bytes
-rw-r--r--Documentation/HTML/images/kshark-open.pngbin0 -> 58572 bytes
-rw-r--r--Documentation/HTML/images/kshark-plot-cpu-1.pngbin0 -> 8385 bytes
-rw-r--r--Documentation/HTML/images/kshark-plot-cpu-2.pngbin0 -> 8453 bytes
-rw-r--r--Documentation/HTML/images/kshark-plot-cpu-result.pngbin0 -> 59326 bytes
-rw-r--r--Documentation/HTML/images/kshark-plot-menu.pngbin0 -> 61670 bytes
-rw-r--r--Documentation/HTML/images/kshark-plot-task-measure-preempt.pngbin0 -> 65759 bytes
-rw-r--r--Documentation/HTML/images/kshark-plot-task-measure.pngbin0 -> 65673 bytes
-rw-r--r--Documentation/HTML/images/kshark-plot-task-result.pngbin0 -> 65607 bytes
-rw-r--r--Documentation/HTML/images/kshark-plot-task-select.pngbin0 -> 26263 bytes
-rw-r--r--Documentation/HTML/images/kshark-plot-task-zoom-1.pngbin0 -> 66467 bytes
-rw-r--r--Documentation/HTML/images/kshark-select-a-1.pngbin0 -> 59254 bytes
-rw-r--r--Documentation/HTML/images/kshark-select-b-1.pngbin0 -> 59400 bytes
-rw-r--r--Documentation/HTML/images/kshark-zoom-in-2.pngbin0 -> 63059 bytes
-rw-r--r--Documentation/HTML/images/kshark-zoom-in-3.pngbin0 -> 59020 bytes
-rw-r--r--Documentation/HTML/images/kshark-zoom-in-select.pngbin0 -> 60206 bytes
-rw-r--r--Documentation/HTML/images/kshark-zoom-out-select.pngbin0 -> 62821 bytes
-rw-r--r--Documentation/HTML/index.html653
-rw-r--r--Documentation/Makefile20
-rw-r--r--Makefile32
-rw-r--r--kernel-shark.c1241
-rw-r--r--kernel-shark.h15
-rw-r--r--parse-events.h12
-rw-r--r--parse-filter.c57
-rw-r--r--parse-utils.c105
-rw-r--r--trace-compat.c38
-rw-r--r--trace-compat.h6
-rw-r--r--trace-dialog.c277
-rw-r--r--trace-filter.c564
-rw-r--r--trace-filter.h26
-rw-r--r--trace-graph-main.c124
-rw-r--r--trace-graph.c216
-rw-r--r--trace-graph.h10
-rw-r--r--trace-gui.h44
-rw-r--r--trace-hash.c63
-rw-r--r--trace-hash.h2
-rw-r--r--trace-util.c67
-rw-r--r--trace-view-main.c358
-rw-r--r--trace-view-store.c1
-rw-r--r--trace-view.c109
-rw-r--r--trace-view.h6
-rw-r--r--trace-xml.c248
-rw-r--r--trace-xml.h62
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>
41KernelShark is a front end reader of <b>trace-cmd(1)</b> output. "trace-cmd record"
42and "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>
49The application has two main viewing areas split by a paned divider. The top half
50is a graphical display of the data and the bottom half is a list view of each
51event. 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>
59The graph information line displays the timestamp of various locations.
60The Pointer: shows the timestamp of where the mouse pointer is. The Cursor: is
61the timestamp of the cursor location. To select a cursor location, double click
62on the graph. Marker A is set with a left mouse click and Marker B is set
63with a with a left mouse click while holding down the shift key.
64</p>
65
66<p>
67The 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>
75and the plot area:
76</p>
77
78<img src="images/kshark-graph-plot-area.png">
79
80<p>
81The plot area contains the data of the given plot, where plots can be per CPU or
82per task. The top of the plot area shows a timeline. The numbers in the timeline
83are seconds. The time in the timeline is taken from the timestamps within
84the trace.dat file which are architecture dependent. The time usually is the timestamp
85from when the system started.
86</p>
87
88<p>
89Below 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>
97The list area contains the Page of the list. The list can hold a maximum of
981 million entries per page. If the trace data contains more than a million
99entries, then the list will have more than one page.
100</p>
101
102<p>
103The list area also contains a search field to search for elements in the
104list.
105</p>
106
107<h1><a name="graph">The Graph View</a></h1>
108
109<p>
110The graph view of kernelshark shows graphical plots of the data stored in
111the trace.dat file. The data plots are per CPU or per task.
112When there are too many events within the resolution of the graph,
113the plots will appear as a rainbow colored bar. To make more sense out of
114the graphs, you need to zoom into a given location to see the details of
115that time frame more clearly.
116</p>
117
118<h2><a name="graph-zoom-in">Zooming In</a></h2>
119
120<p>
121To zoom in, left mouse click and hold and then drag the mouse right, release
122to zoom. When you click the left mouse button a line will appear and stay
123at that location. When you move the mouse to the right, another line appears
124and will follow the mouse. When you release the mouse button, the area
125between the two lines become the new width of the screen. That is, the graph
126zooms in until the lines match the width of the screen. This allows you to
127zoom into a specific location.
128</p>
129
130<img src="images/kshark-zoom-in-select.png">
131
132<p>
133The area that you selected will now become the new width of the viewable area.
134The smaller the selection, the deeper the zoom. Note, that you must select 10
135pixels to zoom in. Less than 10 pixels will cancel the zoom. You can continue zooming
136in until you get more details.
137</p>
138
139<img src="images/kshark-zoom-in-3.png">
140
141<p>
142To save on resources, when zooming in, the beginning
143and end of the full trace may not be reachable with the horizontal scroll bar.
144If a plot contains no events within the reachable area, then the line will be empty,
145as CPU 1 is in the above image.
146</p>
147
148<p>
149CPU 0 shows two tasks that were running. One task
150is given a pink/red color and the other a green color. The think colored
151horizontal bar represents a task other than idle was running. The small
152lines that jet out of the bar are where events occur.
153</p>
154
155<p>
156If you zoom in enough such that a single event has enough room between itself
157and other events, the type of event and the name and PID of the task that was running will appear
158over the event.
159</p>
160
161<h2><a name="graph-zoom-out">Zooming Out</a></h2>
162
163<p>
164To zoom back out, left mouse click and hold and then drag the mouse left.
165This time the width between the two lines will become a single pixel.
166The farther apart the lines are, the farther the zoom out will be.
167Zoom 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>
173When the mouse is over an event, a tool tip will appear showing the event name,
174the <a href="#latency">latency data</a>, the event info, the timestamp and the task
175name 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>
183There are two markers that can be placed on the graph as well as a cursor.
184Marker 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.
186Marker A is represented by a green line:
187</p>
188
189<img src="images/kshark-select-a-1.png">
190
191<p>
192To set Marker B, press and hold the shift key and click the left mouse button.
193Marker B will show up in red.
194</p>
195
196<img src="images/kshark-select-b-1.png">
197
198<p>
199When both the A and B markers are set, the <a href="#graph-info-line">graph info area</a>
200will show the timestamp of where the A and B markers are, as well as the difference
201between 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>
207Double clicking on the graph will set the cursor. The cursor is a blue line, and when
208it is set, it will also select the event in the list view that is the closest event at the
209timeline of where the cursor was selected.
210</p>
211
212<img src="images/kshark-cursor-1.png">
213
214<p>
215The above shows that list item 217448 (sys_exit) was the closest event to where
216the cursor was selected.
217</p>
218
219<p>
220Note 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>
226The graph data is represented by plots. The data on the plots is either CPU specific or
227task specific. If it is CPU specific, then the data is the timeline of events that
228happened on a given CPU (which CPU is shown in the <a href="#graph-plot-title">plot title area</a>).
229If the plot is task specific, then the timeline of events is for the given
230task regardless of what CPU it was on at the time. The task name is also shown
231in the plot title area.
232</p>
233
234<p>
235By default, all the CPUs within the loaded trace.dat file are plotted.
236There are two ways to plot a task. One way is to right mouse click over a
237displayed task in the graph and select the plot option. This will add the
238task plot directly underneath the CPU plot that the task was on where
239the 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>
247Selecting the "Tasks" menu item will bring up a dialog with all the tasks
248that were found in the trace data.
249</p>
250
251<img src="images/kshark-plot-task-select.png">
252
253<p>
254Selecting a task in this dialog will add the task plot to the bottom of the graph
255area. 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>
261The colors in the task plots are different depending on which CPU the task
262was on at the time. The CPU plots change colors as different tasks run
263on the CPU, and the task plots change color depending on what CPU the task
264is running on. This makes it easy to see how much a task
265bounces around the CPUs. Zooming in on a task plot also shows some more
266characteristics of the task.
267</p>
268
269<img src="images/kshark-plot-task-zoom-1.png">
270
271<p>
272The hollow green bar that is shown in front of some events in the task
273plot represents when the task was woken up from a sleeping state to
274when it actually ran. The hollow red bar between some events shows that
275the task was preempted by another task even though that task
276was still runnable.
277</p>
278
279<p>
280Since 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>
287The above shows that the epiphany-browser with PID 28072 had a 479 microsecond wake up
288latency. 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>
296Selecting the "CPUs" plot menu item pops up a dialog that shows the available CPUs that
297can be plotted.
298<p>
299
300<img src="images/kshark-plot-cpu-1.png">
301
302<p>
303Removing 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>
315The list view is in the bottom half paned window and can be expanded or shortened
316with the paned handle.
317</p>
318
319<img src="images/kshark-list-adjust.png">
320
321<p>
322The top of the list view contains the <a href="#list-area">list area</a> which has the list page, list
323search, and "graph follows" toggle button. If more than a million events are stored in the
324list, then each set of million will be on a different page.
325</p>
326
327<p>
328The 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
335resolution.
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>
360The list search can find an event based on the contents in a row. Select a column, a
361match criteria and the content to match to find the next row that matches the
362search. 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
367as 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>
373The 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>
378A single click on a row will select the row, but a double click on a row will select
379that row as well as set the graph cursor to the location of that event. If the plot
380that the event is on is not visible then the graph will adjust its vertical view area
381to 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>
388When the "graph follows" toggle is set, then even a single click on a row
389will move the graph cursor. With the mouse focus on the list, using the keyboard
390up and down arrow keys will move the selection of the list as well as the graph
391cursor.
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>
401The amount of data that can be stored in a trace.dat file can be enormous.
402To make any sense out of some traces, it may be required to only display various
403events. The same can be true about tasks.
404Kernelshark has filters for tasks as well as for events. The task filter
405affects both the graph and the list, but the graph and list each have a separate
406event filter.
407<p>
408
409<h2><a name="filter-task">Task Filter</a></h2>
410
411<p>
412The task filter is currently set by a right mouse click over
413an event on either the graph or the list view, and by selecting the option to add or remove the
414task to/from the task filter. The tasks within the task filter are the same for
415both the graph and list, but each can be enabled separately.
416</p>
417
418<p>
419There 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>
428If there are any tasks within the Task Filter then only those tasks will be displayed
429when the filter is enabled. Any task within the Hide Tasks filter will not be
430displayed, 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>
436When 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>
442When a task is not in the "Task Filter", the pop up will show the
443menu item "Add task". When a task is in the "Task Filter" the
444pop up will show "Remove task".
445</p>
446
447<p>
448When a task is not in the "Hide Tasks", the pop up will show the
449menu item "Hide task". When a task is in the "Hide Tasks", the
450pop up will show "Show task".
451</p>
452
453<h4>The scheduling events</h4>
454
455<p>
456The events "sched_switch", "sched_wakeup", and "sched_wakeup_new" are treated
457differently 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
459then that event is visible regardless if the other task should be hidden.
460This 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>
466The graph and list view each have their own event filter. The event filters
467are enabled through the Filter menu on the top menu-bar.
468</p>
469
470<img src="images/kshark-filter.png">
471
472<p>
473Selecting either the "list events" or "graph events" will bring up the event
474dialog with the events that are visible selected.
475</p>
476
477<p>
478Note: these do not mean that the events exist in the trace.dat file. They are
479selected if the events are not to be hidden. Events that do not exist in the trace
480will 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>
486Clicking on "All" or any of the systems will either deselect all events underneath
487or select all events underneath depending on the previous state of the box being
488selected. 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>
494If it is desired that the graph and list view have the same events filtered, then just
495set up the desired filtering in one and then synchronize the other through
496the 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
503as 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
505as what is in the graph filter.
506</ul>
507
508<h3><a name="filter-adv-event">Advanced Event Filter</a></h3>
509
510<p>
511Filtering on events may not be enough. The ability to filter on the content
512of individual events may be needed. In order to accomplish this, the advanced event
513filtering is used. Selecting the "list advanced event" or "graph advanced event"
514from the Filter menu will pop up the advanced event filtering dialog.
515The 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>
521The "Filter:" entry at the bottom of the dialog is where the advanced filter is
522written. Above that is helper buttons to pick events, operations and event fields.
523The 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 := '&gt;' | '&lt;' | '==' | '&gt;=' | '&lt;=' | '!='
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 := '+' | '-' | '*' | '/' | '&lt;&lt;' | '&gt;&gt;' | '&' | '!'
542</pre>
543
544<p>
545Spaces are ignored. The example used in the dialog figure:
546</p>
547
548<pre>
549 sched/sched_switch : next_prio &lt; 100 && (prev_prio &gt; 100 && prev_pid != 0)
550</pre>
551
552<p>
553The <tt>sched/</tt> is not necessary because without it, the filter will process all events
554named <tt>sched_switch</tt>, and since there is only one event
555that has that name, including the <tt>sched/</tt> is redundant.
556<p>
557
558<p>
559The <tt>next_prio</tt>, <tt>prev_prio</tt> and <tt>prev_pid</tt> are all
560event fields of the <tt>sched_swich</tt> event.
561</p>
562
563<p>
564If just <tt>sched</tt> was used and the <tt>/sched_switch</tt> was omitted, it would
565still be a valid filter, but it would behave differently. By just specifying
566a system, the filter will run on all events within that system. When a field
567is 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>
576The above two filters are not equivalent. They are for the <tt>sched_switch</tt> event,
577but not for the other events. The first filter will return false for all events
578that do not contain the <tt>prev_pid</tt> field, but the second filter would return
579true for all events that do not contain that field. Again, if the event does
580not contain a field, just that compare will be evaluated to false, not the entire
581expression. This means for events that do not have the <tt>prev_pid</tt> field,
582the above filters would be equivalent to:
583</p>
584
585<pre>
586 sched : FALSE
587 sched : !(FALSE)
588</pre>
589
590<p>
591Letting filters contain fields that do not belong to an event be valid
592allows for various tricks where two events can share the same
593filter.
594</p>
595
596<pre>
597 sched_switch, sched_wake.* : next_pid == 1 || pid == 1
598</pre>
599
600<p>
601The schedule events that have <tt>next_pid</tt> and not <tt>pid</tt> as a field
602will 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
604part of the <tt>||</tt>
605</p>
606
607<p>
608Notice that event names in the filter can be regular expressions.
609</p>
610
611<p>
612String 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>
621The available regular expressions are described in <b>regex(7)</b>.
622</p>
623
624<p>
625Note: When adding an advanced filter, all non-advanced filters
626(added by the event filter dialog box) will be removed, and only the advanced
627filters will stay. But non-advanced filters may be added after advanced
628filters have been. The events that have advanced filters will be shaded
629in the event filter dialog:
630<p>
631
632<img src="images/kshark-filter-event-adv-list.png">
633
634<p>
635Just do not click on the advanced filter box and hit "Apply" unless you want to remove
636the advanced filter. Non-advanced filters can now be selected without affecting
637the advanced filters.
638</p>
639
640<img src="images/kshark-filter-list-adv-irq.png">
641
642<p>
643When advanced filters already exist when the advanced filter dialog box pops up,
644they will be listed in the area at the top of the dialog. Although
645one filter may have been written, the list will be per event. A check box
646is to the left of the filter. When checked, the filter will be deleted if
647the "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
90install: $(MAN1_INSTALL) $(MAN5_INSTALL) 90html_dir = $(src)/HTML
91image_dir = $(html_dir)/images
92
93HTML = $(wildcard $(html_dir)/*.html)
94IMGS = $(wildcard $(image_dir)/*.png)
95
96HTML_INSTALL = $(subst .html,.html.install,$(HTML))
97IMGS_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
106GUI_INSTALL = $(HTML_INSTALL) $(IMGS_INSTALL)
107
108install: $(MAN1_INSTALL) $(MAN5_INSTALL) $(GUI_INSTALL)
91 109
92clean: 110clean:
93 (cd $(obj); \ 111 (cd $(obj); \
diff --git a/Makefile b/Makefile
index fb06e26..a278510 100644
--- a/Makefile
+++ b/Makefile
@@ -30,8 +30,13 @@ bindir_relative = bin
30bindir = $(prefix)/$(bindir_relative) 30bindir = $(prefix)/$(bindir_relative)
31man_dir = $(prefix)/share/man 31man_dir = $(prefix)/share/man
32man_dir_SQ = '$(subst ','\'',$(man_dir))' 32man_dir_SQ = '$(subst ','\'',$(man_dir))'
33html_install = $(prefix)/share/kernelshark/html
34html_install_SQ = '$(subst ','\'',$(html_install))'
35img_install = $(prefix)/share/kernelshark/html/images
36img_install_SQ = '$(subst ','\'',$(img_install))'
33 37
34export man_dir man_dir_SQ INSTALL 38export man_dir man_dir_SQ html_install html_install_SQ INSTALL
39export img_install img_install_SQ
35export DESTDIR DESTDIR_SQ 40export DESTDIR DESTDIR_SQ
36 41
37ifeq ($(prefix),$(HOME)) 42ifeq ($(prefix),$(HOME))
@@ -46,6 +51,9 @@ PLUGIN_DIR_SQ = '$(subst ','\'',$(PLUGIN_DIR))'
46PYTHON_DIR_SQ = '$(subst ','\'',$(PYTHON_DIR))' 51PYTHON_DIR_SQ = '$(subst ','\'',$(PYTHON_DIR))'
47endif 52endif
48 53
54HELP_DIR = -DHELP_DIR=$(html_install)
55HELP_DIR_SQ = '$(subst ','\'',$(HELP_DIR))'
56
49# copy a bit from Linux kbuild 57# copy a bit from Linux kbuild
50 58
51ifeq ("$(origin V)", "command line") 59ifeq ("$(origin V)", "command line")
@@ -120,7 +128,7 @@ python_dir_SQ = $(subst ','\'',$(python_dir))
120LIBS = -L. -ltracecmd -ldl 128LIBS = -L. -ltracecmd -ldl
121LIB_FILE = libtracecmd.a 129LIB_FILE = libtracecmd.a
122 130
123PACKAGES= gtk+-2.0 131PACKAGES= gtk+-2.0 libxml-2.0
124 132
125ifndef BUILDGUI 133ifndef BUILDGUI
126 BUILDGUI = 0 134 BUILDGUI = 0
@@ -148,6 +156,7 @@ REBUILD_GUI = /bin/true
148G = 156G =
149N = @/bin/true || 157N = @/bin/true ||
150 158
159CONFIG_FLAGS += $(HELP_DIR_SQ)
151else 160else
152 161
153CONFIG_INCLUDES = 162CONFIG_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
249TRACE_GUI_OBJS = trace-filter.o trace-compat.o trace-hash.o trace-dialog.o \
250 trace-xml.o
240TRACE_CMD_OBJS = trace-cmd.o trace-usage.o trace-read.o trace-split.o trace-listen.o 251TRACE_CMD_OBJS = trace-cmd.o trace-usage.o trace-read.o trace-split.o trace-listen.o
241TRACE_VIEW_OBJS = trace-view.o trace-view-store.o trace-filter.o trace-compat.o \ 252TRACE_VIEW_OBJS = trace-view.o trace-view-store.o
242 trace-hash.o 253TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o trace-plot-cpu.o trace-plot-task.o
243TRACE_GRAPH_OBJS = trace-graph.o trace-compat.o trace-hash.o trace-filter.o \ 254TRACE_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 255TRACE_GRAPH_MAIN_OBJS = trace-graph-main.o $(TRACE_GRAPH_OBJS) $(TRACE_GUI_OBJS)
245TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS) 256KERNEL_SHARK_OBJS = $(TRACE_VIEW_OBJS) $(TRACE_GRAPH_OBJS) $(TRACE_GUI_OBJS) \
246TRACE_GRAPH_MAIN_OBJS = trace-graph-main.o $(TRACE_GRAPH_OBJS) 257 kernel-shark.o
247KERNEL_SHARK_OBJS = $(TRACE_VIEW_OBJS) $(TRACE_GRAPH_OBJS) kernel-shark.o 258
248 259PEVENT_LIB_OBJS = parse-events.o trace-seq.o parse-filter.o parse-utils.o
249PEVENT_LIB_OBJS = parse-events.o trace-seq.o parse-filter.o
250TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \ 260TCMD_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 */
74static 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
129static 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
116static void free_info(struct shark_info *info) 201static 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
226static 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
244static 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
257static 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
271static 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
137static void 284static void
138/* Callback for the clicked signal of the Load button */ 285/* Callback for the clicked signal of the Load button */
139load_clicked (gpointer data) 286load_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 */
308static void
309load_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 */
398static void
399save_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 */
191static void 465static void
192list_events_clicked (gpointer data) 466sync_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 */
216static void 551static void
217graph_events_clicked (gpointer data) 552sync_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 */ 614static void filter_list_enable_clicked (gpointer data);
615
233static void 616static void
234adv_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
652static void
653update_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
664static void
665update_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 */
677static 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 */
255static void 707static void
256adv_graph_filter_clicked (gpointer data) 708list_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
716static void
717list_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
725static 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
265static void 758static void
266sync_graph_events_to_list_clicked (gpointer data) 759update_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
771static void
772update_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 */
785static 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
806static void
807graph_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
816static void
817graph_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 */
827static void
828list_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
856static void
857graph_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
289static void 874static void
290sync_list_events_to_graph_clicked (gpointer data) 875graph_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 */
891static void
892adv_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
916static void
917graph_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 */
933static void
934adv_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 */
1007static void
1008help_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 */
1021static void
1022help_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
365static void graph_follows_tree(struct shark_info *info, 1034static 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
427filter_list_enable_clicked (gpointer data) 1096filter_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
441static void 1119static void
1120filter_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
1141static void
442filter_add_task_clicked (gpointer data) 1142filter_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
1157static void
1158filter_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
452static void 1165static 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
1180static void
1181filter_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
464static void 1188static 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
1206static void
1207filter_graph_clear_tasks_clicked (gpointer data)
1208{
1209 struct shark_info *info = data;
1210
1211 trace_graph_clear_tasks(info->ginfo);
1212}
1213
474static void graph_check_toggle(gpointer data, GtkWidget *widget) 1214static 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
1221static 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
481static gboolean 1232static gboolean
482do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) 1233do_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 */
350void die(char *fmt, ...); 351void die(char *fmt, ...);
351void *malloc_or_die(unsigned int size); 352void *malloc_or_die(unsigned int size);
352void warning(char *fmt, ...); 353void warning(char *fmt, ...);
353void pr_stat(char *fmt, ...); 354void pr_stat(char *fmt, ...);
354 355
356/* Always available */
357void __die(char *fmt, ...);
358void __warning(char *fmt, ...);
359void __pr_stat(char *fmt, ...);
360
361void __vdie(char *fmt, ...);
362void __vwarning(char *fmt, ...);
363void __vpr_stat(char *fmt, ...);
364
355static inline unsigned short 365static 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);
702int pevent_update_trivial(struct event_filter *dest, struct event_filter *source, 712int 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
715int 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 */
2038int 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
9void __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
25void __die(char *fmt, ...)
26{
27 va_list ap;
28
29 va_start(ap, fmt);
30 __vdie(fmt, ap);
31 va_end(ap);
32}
33
34void __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
43void __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
55void __warning(char *fmt, ...)
56{
57 va_list ap;
58
59 va_start(ap, fmt);
60 __vwarning(fmt, ap);
61 va_end(ap);
62}
63
64void __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
73void __vpr_stat(char *fmt, va_list ap)
74{
75 vprintf(fmt, ap);
76 printf("\n");
77}
78
79void __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
88void __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
97void __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
77gboolean gtk_show_uri(GdkScreen *screen, const gchar *uri,
78 guint32 timestamp, GError **error)
79{
80 return FALSE;
81}
82
83void 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
104void 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);
43gdouble gtk_adjustment_get_page_size(GtkAdjustment *adj); 44gdouble gtk_adjustment_get_page_size(GtkAdjustment *adj);
44gdouble gtk_adjustment_get_upper(GtkAdjustment *adj); 45gdouble gtk_adjustment_get_upper(GtkAdjustment *adj);
45gdouble gtk_adjustment_get_lower(GtkAdjustment *adj); 46gdouble gtk_adjustment_get_lower(GtkAdjustment *adj);
47gboolean gtk_show_uri(GdkScreen *screen, const gchar *uri,
48 guint32 timestamp, GError **error);
49
50void 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
51GtkWidget *gtk_tree_view_column_get_tree_view(GtkTreeViewColumn *col); 56GtkWidget *gtk_tree_view_column_get_tree_view(GtkTreeViewColumn *col);
57void 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
35static GtkWidget *statusbar;
36static GtkWidget *statuspix;
37static GString *statusstr;
38
39static GtkWidget *parent_window;
40
41void 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 */
77void trace_dialog_register_window(GtkWidget *window)
78{
79 parent_window = window;
80}
81
82void 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
113static void
114status_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
156static gboolean
157do_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
179static gboolean
180button_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
188GtkWidget *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
212void 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
226void 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
260gchar *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
61struct 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
102struct 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
110static GtkTreeModel *create_event_combo_model(struct pevent *pevent) 98static GtkTreeModel *create_event_combo_model(struct pevent *pevent)
@@ -319,7 +307,6 @@ static void event_combo_changed(GtkComboBox *combo, gpointer data)
319static void insert_combo_text(struct event_combo_info *info, 307static 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 */
510static void
511adv_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
538static GtkTreeModel * 495static GtkTreeModel *
539create_tree_filter_model(struct tracecmd_input *handle, 496create_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
800struct task_helper {
801 trace_task_cb_func func;
802 GtkTreeView *view;
803 gboolean start;
804 gpointer data;
805};
806
807enum { 758enum {
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 */
854static void
855task_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
882static GtkTreeModel * 804static GtkTreeModel *
883create_task_model(struct tracecmd_input *handle, 805create_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
961static void task_cursor_changed(gpointer data, GtkTreeView *treeview) 883static 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)
999static GtkWidget * 921static GtkWidget *
1000create_task_view(struct tracecmd_input *handle, 922create_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
1133enum { 1056enum {
@@ -1602,9 +1525,9 @@ static gint update_system_events(GtkTreeModel *model,
1602 return size; 1525 return size;
1603} 1526}
1604 1527
1605static void accept_events(struct event_filter_helper *event_helper) 1528static 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 */
1646static void
1647event_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
1672static void filter_event_dialog(struct tracecmd_input *handle, 1567static 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
1786static void destroy_cpu_helper(struct cpu_filter_helper *cpu_helper) 1675static 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 */
1794static void
1795cpu_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
1829void cpu_toggle(gpointer data, GtkWidget *widget) 1684void cpu_toggle(gpointer data, GtkWidget *widget)
@@ -1875,8 +1730,8 @@ void cpu_toggle(gpointer data, GtkWidget *widget)
1875void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpus_selected, gint cpus, 1730void 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
2017static void add_system_str(gchar ***systems, char *system, int count) 1884static 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
2029int 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
2074int 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
2095int 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
2170int 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
2198int 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
2237int 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
26struct event_filter_list { 28struct 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,
133void trace_filter_cpu_dialog(gboolean all_cpus, guint64 *cpu_mask_selected, gint cpus, 135void 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
138void trace_array_add(gint **array, gint *count, gint val);
139
140/* save and load filters */
141int trace_filter_save_events(struct tracecmd_xml_handle *handle,
142 struct event_filter *filter);
143int trace_filter_save_tasks(struct tracecmd_xml_handle *handle,
144 struct filter_task *filter);
145int trace_filter_load_events(struct event_filter *event_filter,
146 struct tracecmd_xml_handle *handle,
147 struct tracecmd_xml_system_node *node);
148int trace_filter_load_task_filter(struct filter_task *filter,
149 struct tracecmd_xml_handle *handle,
150 struct tracecmd_xml_system_node *node);
151int 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);
155int 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
138int str_cmp(const void *a, const void *b); 162int str_cmp(const void *a, const void *b);
139int id_cmp(const void *a, const void *b); 163int id_cmp(const void *a, const void *b);
140 164
141void 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 */
158static void
159load_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 */
185static void
186save_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
161void trace_graph(int argc, char **argv) 211void 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
551void 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
583void trace_graph_refresh_filters(struct graph_info *ginfo)
584{
585 trace_graph_update_filters(ginfo, ginfo->task_filter,
586 ginfo->hide_tasks);
587}
588
551static void 589static void
552filter_clear_tasks_clicked (gpointer data) 590filter_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
769static void button_press(struct graph_info *ginfo, gint x, guint state) 807static void draw_info_box(struct graph_info *ginfo, const gchar *buffer,
808 gint x, gint y);
809
810static void stop_zoom_tip(struct graph_info *ginfo)
811{
812 clear_info_box(ginfo);
813}
814
815static 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
825static 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
2461static 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
2494int 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
2544int 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
2569static 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
2575static 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
2581static 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
2398struct graph_info * 2587struct graph_info *
2399trace_graph_create_with_callbacks(struct tracecmd_input *handle, 2588trace_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
28struct graph_info; 29struct 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);
307gint *trace_graph_task_list(struct graph_info *ginfo); 308gint *trace_graph_task_list(struct graph_info *ginfo);
308 309
310int trace_graph_load_filters(struct graph_info *ginfo,
311 struct tracecmd_xml_handle *handle);
312int trace_graph_save_filters(struct graph_info *ginfo,
313 struct tracecmd_xml_handle *handle);
314void trace_graph_update_filters(struct graph_info *ginfo,
315 struct filter_task *task_filter,
316 struct filter_task *hide_tasks);
317void trace_graph_refresh_filters(struct graph_info *ginfo);
318
309/* plots */ 319/* plots */
310void trace_graph_plot_free(struct graph_info *ginfo); 320void trace_graph_plot_free(struct graph_info *ginfo);
311void trace_graph_plot_init(struct graph_info *ginfo); 321void 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
26enum trace_dialog_type {
27 TRACE_GUI_INFO,
28 TRACE_GUI_WARNING,
29 TRACE_GUI_ERROR,
30};
31
32GtkWidget *trace_status_bar_new(void);
33
34void trace_dialog_register_window(GtkWidget *window);
35
36void trace_show_help(GtkWidget *window, const gchar *link, GError **error);
37
38void trace_dialog(GtkWindow *parent, enum trace_dialog_type type,
39 gchar *message, ...);
40
41gchar *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
160int *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 */
193int 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);
42struct filter_task *filter_task_hash_alloc(void); 42struct filter_task *filter_task_hash_alloc(void);
43void filter_task_hash_free(struct filter_task *hash); 43void filter_task_hash_free(struct filter_task *hash);
44struct filter_task *filter_task_hash_copy(struct filter_task *hash); 44struct filter_task *filter_task_hash_copy(struct filter_task *hash);
45int *filter_task_pids(struct filter_task *hash);
46int filter_task_compare(struct filter_task *hash1, struct filter_task *hash2);
45 47
46static inline gint filter_task_count(struct filter_task *hash) 48static 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 @@
38int tracecmd_disable_sys_plugins; 38int tracecmd_disable_sys_plugins;
39int tracecmd_disable_plugins; 39int 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
56void __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
75void __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
91void __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
102void __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
112int __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
121void parse_cmdlines(struct pevent *pevent, 54void 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 @@
38static char *input_file; 44static char *input_file;
39 45
40struct trace_tree_info { 46struct 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
45void usage(char *prog) 56void 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 */
86static void
87load_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 */
116static void
117save_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 226static void
166static GtkTreeModel * 227filter_list_clicked (gpointer data)
167create_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
245static 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
264static 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
271static 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
278static void
279filter_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
287static gboolean
288do_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); 417static gboolean
173 gtk_list_store_append(store, &iter); 418button_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
180void trace_view(int argc, char **argv) 426void 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
874int 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
909static 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
941int 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
27void 28void
28trace_view_load(GtkWidget *view, struct tracecmd_input *handle, 29trace_view_load(GtkWidget *view, struct tracecmd_input *handle,
@@ -65,4 +66,9 @@ void trace_view_search_setup(GtkBox *box, GtkTreeView *treeview);
65 66
66gint trace_view_get_selected_row(GtkWidget *treeview); 67gint trace_view_get_selected_row(GtkWidget *treeview);
67 68
69int trace_view_save_filters(struct tracecmd_xml_handle *handle,
70 GtkTreeView *treeview);
71int 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
33struct tracecmd_xml_handle {
34 xmlTextWriterPtr writer;
35 xmlDocPtr doc;
36};
37
38struct tracecmd_xml_system {
39 struct tracecmd_xml_handle *handle;
40 xmlXPathObjectPtr result;
41 xmlNodePtr cur;
42};
43
44#define TRACE_ENCODING "UTF-8"
45
46int 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
61struct 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
93int 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
107int 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
118void tracecmd_xml_end_system(struct tracecmd_xml_handle *handle)
119{
120 xmlTextWriterEndElement(handle->writer);
121}
122
123void tracecmd_xml_end_sub_system(struct tracecmd_xml_handle *handle)
124{
125 xmlTextWriterEndElement(handle->writer);
126}
127
128void 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
146struct 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
164struct tracecmd_xml_system *
165tracecmd_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
195struct tracecmd_xml_system_node *
196tracecmd_xml_system_node(struct tracecmd_xml_system *system)
197{
198 return (struct tracecmd_xml_system_node *)system->cur;
199}
200
201const 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
207struct tracecmd_xml_system_node *
208tracecmd_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
214struct tracecmd_xml_system_node *
215tracecmd_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
221const 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
228void tracecmd_xml_free_system(struct tracecmd_xml_system *system)
229{
230 xmlXPathFreeObject(system->result);
231 free(system);
232}
233
234int 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
24struct tracecmd_xml_handle;
25struct tacecmd_xml_system;
26struct tacecmd_xml_system_node;
27
28struct tracecmd_xml_handle *tracecmd_xml_create(const char *name, const char *version);
29struct tracecmd_xml_handle *tracecmd_xml_open(const char *name);
30void tracecmd_xml_close(struct tracecmd_xml_handle *handle);
31
32int tracecmd_xml_start_system(struct tracecmd_xml_handle *handle,
33 const char *system);
34void tracecmd_xml_end_system(struct tracecmd_xml_handle *handle);
35
36int tracecmd_xml_start_sub_system(struct tracecmd_xml_handle *handle,
37 const char *subsystem);
38void tracecmd_xml_end_sub_system(struct tracecmd_xml_handle *handle);
39
40int tracecmd_xml_write_element(struct tracecmd_xml_handle *handle,
41 const char *obj,
42 const char *fmt, ...);
43
44struct tracecmd_xml_handle *tracecmd_xml_open(const char *file);
45
46struct tracecmd_xml_system *
47tracecmd_xml_find_system(struct tracecmd_xml_handle *handle,
48 const char *system);
49void tracecmd_xml_free_system(struct tracecmd_xml_system *system);
50struct tracecmd_xml_system_node *
51tracecmd_xml_system_node(struct tracecmd_xml_system *system);
52const char *tracecmd_xml_node_type(struct tracecmd_xml_system_node *tnode);
53struct tracecmd_xml_system_node *
54tracecmd_xml_node_child(struct tracecmd_xml_system_node *tnode);
55struct tracecmd_xml_system_node *
56tracecmd_xml_node_next(struct tracecmd_xml_system_node *tnode);
57const char *tracecmd_xml_node_value(struct tracecmd_xml_handle *handle,
58 struct tracecmd_xml_system_node *tnode);
59int tracecmd_xml_system_exists(struct tracecmd_xml_handle *handle,
60 const char *system);
61
62#endif /* __TRACE_XML_H */