- add sources.
[platform/framework/web/crosswalk.git] / src / tools / stats_viewer / stats_viewer.cs
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 using System;\r
6 using System.Collections;\r
7 using System.Collections.Generic;\r
8 using System.ComponentModel;\r
9 using System.Data;\r
10 using System.Diagnostics;\r
11 using System.Drawing;\r
12 using System.Text;\r
13 using System.Windows.Forms;\r
14 using System.IO;\r
15 \r
16 namespace StatsViewer {\r
17   public partial class StatsViewer : Form  {\r
18     /// <summary>\r
19     /// Create a StatsViewer.\r
20     /// </summary>\r
21     public StatsViewer() {\r
22       InitializeComponent();\r
23     }\r
24 \r
25     #region Protected Methods\r
26     /// <summary>\r
27     /// Callback when the form loads.\r
28     /// </summary>\r
29     /// <param name="e"></param>\r
30     protected override void OnLoad(EventArgs e) {\r
31       base.OnLoad(e);\r
32 \r
33       timer_ = new Timer();\r
34       timer_.Interval = kPollInterval;\r
35       timer_.Tick += new EventHandler(PollTimerTicked);\r
36       timer_.Start();\r
37     }\r
38     #endregion\r
39 \r
40     #region Private Methods\r
41     /// <summary>\r
42     /// Attempt to open the stats file.\r
43     /// Return true on success, false otherwise.\r
44     /// </summary>\r
45     private bool OpenStatsFile() {\r
46       StatsTable table = new StatsTable();\r
47       if (table.Open(kStatsTableName)) {\r
48         stats_table_ = table;\r
49         return true;\r
50       }\r
51       return false;\r
52     }\r
53 \r
54     /// <summary>\r
55     /// Close the open stats file.\r
56     /// </summary>\r
57     private void CloseStatsFile() {\r
58       if (this.stats_table_ != null)\r
59       {\r
60         this.stats_table_.Close();\r
61         this.stats_table_ = null;\r
62         this.listViewCounters.Items.Clear();\r
63       }\r
64     }\r
65 \r
66     /// <summary>\r
67     /// Updates the process list in the UI.\r
68     /// </summary>\r
69     private void UpdateProcessList() {\r
70       int current_pids = comboBoxFilter.Items.Count;\r
71       int table_pids = stats_table_.Processes.Count;\r
72       if (current_pids != table_pids + 1)  // Add one because of the "all" entry.\r
73       {\r
74         int selected_index = this.comboBoxFilter.SelectedIndex;\r
75         this.comboBoxFilter.Items.Clear();\r
76         this.comboBoxFilter.Items.Add(kStringAllProcesses);\r
77         foreach (int pid in stats_table_.Processes)\r
78           this.comboBoxFilter.Items.Add(kStringProcess + pid.ToString());\r
79         this.comboBoxFilter.SelectedIndex = selected_index;\r
80       }\r
81     }\r
82 \r
83     /// <summary>\r
84     /// Updates the UI for a counter.\r
85     /// </summary>\r
86     /// <param name="counter"></param>\r
87     private void UpdateCounter(IStatsCounter counter) {\r
88       ListView view;\r
89 \r
90       // Figure out which list this counter goes into.\r
91       if (counter is StatsCounterRate)\r
92         view = listViewRates;\r
93       else if (counter is StatsCounter || counter is StatsTimer)\r
94         view = listViewCounters;\r
95       else\r
96         return; // Counter type not supported yet.\r
97 \r
98       // See if the counter is already in the list.\r
99       ListViewItem item = view.Items[counter.name];\r
100       if (item != null)\r
101       {\r
102         // Update an existing counter.\r
103         Debug.Assert(item is StatsCounterListViewItem);\r
104         StatsCounterListViewItem counter_item = item as StatsCounterListViewItem;\r
105         counter_item.Update(counter, filter_pid_);\r
106       }\r
107       else\r
108       {\r
109         // Create a new counter\r
110         StatsCounterListViewItem new_item = null;\r
111         if (counter is StatsCounterRate)\r
112           new_item = new RateListViewItem(counter, filter_pid_);\r
113         else if (counter is StatsCounter || counter is StatsTimer)\r
114           new_item = new CounterListViewItem(counter, filter_pid_);\r
115         Debug.Assert(new_item != null);\r
116         view.Items.Add(new_item);\r
117       }\r
118     }\r
119 \r
120     /// <summary>\r
121     /// Sample the data and update the UI\r
122     /// </summary>\r
123     private void SampleData() {\r
124       // If the table isn't open, try to open it again.\r
125       if (stats_table_ == null)\r
126         if (!OpenStatsFile())\r
127           return;\r
128 \r
129       if (stats_counters_ == null)\r
130         stats_counters_ = stats_table_.Counters();\r
131 \r
132       if (pause_updates_)\r
133         return;\r
134 \r
135       stats_counters_.Update();\r
136 \r
137       UpdateProcessList();\r
138 \r
139       foreach (IStatsCounter counter in stats_counters_)\r
140         UpdateCounter(counter);\r
141     }\r
142 \r
143     /// <summary>\r
144     /// Set the background color based on the value\r
145     /// </summary>\r
146     /// <param name="item"></param>\r
147     /// <param name="value"></param>\r
148     private void ColorItem(ListViewItem item, int value)\r
149     {\r
150       if (value < 0)\r
151         item.ForeColor = Color.Red;\r
152       else if (value > 0)\r
153         item.ForeColor = Color.DarkGreen;\r
154       else\r
155         item.ForeColor = Color.Black;\r
156     }\r
157 \r
158     /// <summary>\r
159     /// Called when the timer fires.\r
160     /// </summary>\r
161     /// <param name="sender"></param>\r
162     /// <param name="e"></param>\r
163     void PollTimerTicked(object sender, EventArgs e) {\r
164       SampleData();\r
165     }\r
166 \r
167     /// <summary>\r
168     /// Called when the interval is changed by the user.\r
169     /// </summary>\r
170     /// <param name="sender"></param>\r
171     /// <param name="e"></param>\r
172     private void interval_changed(object sender, EventArgs e) {\r
173       int interval = 1;\r
174       if (int.TryParse(comboBoxInterval.Text, out interval)) {\r
175         if (timer_ != null) {\r
176           timer_.Stop();\r
177           timer_.Interval = interval * 1000;\r
178           timer_.Start();\r
179         }\r
180       } else {\r
181         comboBoxInterval.Text = timer_.Interval.ToString();\r
182       }\r
183     }\r
184 \r
185     /// <summary>\r
186     /// Called when the user changes the filter\r
187     /// </summary>\r
188     /// <param name="sender"></param>\r
189     /// <param name="e"></param>\r
190     private void filter_changed(object sender, EventArgs e) {\r
191       // While in this event handler, don't allow recursive events!\r
192       this.comboBoxFilter.SelectedIndexChanged -= new System.EventHandler(this.filter_changed);\r
193       if (this.comboBoxFilter.Text == kStringAllProcesses)\r
194         filter_pid_ = 0;\r
195       else\r
196         int.TryParse(comboBoxFilter.Text.Substring(kStringProcess.Length), out filter_pid_);\r
197       SampleData();\r
198       this.comboBoxFilter.SelectedIndexChanged += new System.EventHandler(this.filter_changed);\r
199     }\r
200 \r
201     /// <summary>\r
202     /// Callback when the mouse enters a control\r
203     /// </summary>\r
204     /// <param name="sender"></param>\r
205     /// <param name="e"></param>\r
206     private void mouse_Enter(object sender, EventArgs e) {\r
207       // When the dropdown is expanded, we pause \r
208       // updates, as it messes with the UI.\r
209       pause_updates_ = true;\r
210     }\r
211 \r
212     /// <summary>\r
213     /// Callback when the mouse leaves a control\r
214     /// </summary>\r
215     /// <param name="sender"></param>\r
216     /// <param name="e"></param>\r
217     private void mouse_Leave(object sender, EventArgs e) {\r
218       pause_updates_ = false;\r
219     }\r
220 \r
221     /// <summary>\r
222     /// Called when the user clicks the zero-stats button.\r
223     /// </summary>\r
224     /// <param name="sender"></param>\r
225     /// <param name="e"></param>\r
226     private void buttonZero_Click(object sender, EventArgs e) {\r
227       this.stats_table_.Zero();\r
228       SampleData();\r
229     }\r
230 \r
231     /// <summary>\r
232     /// Called when the user clicks a column heading.\r
233     /// </summary>\r
234     /// <param name="sender"></param>\r
235     /// <param name="e"></param>\r
236     private void column_Click(object sender, ColumnClickEventArgs e) {\r
237       if (e.Column != sort_column_) {\r
238         sort_column_ = e.Column;\r
239         this.listViewCounters.Sorting = SortOrder.Ascending;\r
240       } else {\r
241         if (this.listViewCounters.Sorting == SortOrder.Ascending)\r
242           this.listViewCounters.Sorting = SortOrder.Descending;\r
243         else\r
244           this.listViewCounters.Sorting = SortOrder.Ascending;\r
245       }\r
246 \r
247       this.listViewCounters.ListViewItemSorter =\r
248           new ListViewItemComparer(e.Column, this.listViewCounters.Sorting);\r
249       this.listViewCounters.Sort();\r
250     }\r
251 \r
252     /// <summary>\r
253     /// Called when the user clicks the button "Export".\r
254     /// </summary>\r
255     /// <param name="sender"></param>\r
256     /// <param name="e"></param>\r
257     private void buttonExport_Click(object sender, EventArgs e) {\r
258       //Have to pick a textfile to export to.\r
259       //Saves what is shown in listViewStats in the format: function   value\r
260       //(with a tab in between), so that it is easy to copy paste into a spreadsheet.\r
261       //(Does not save the delta values.)\r
262       TextWriter tw = null;\r
263       try {\r
264         saveFileDialogExport.CheckFileExists = false;\r
265         saveFileDialogExport.ShowDialog();\r
266         tw = new StreamWriter(saveFileDialogExport.FileName);\r
267 \r
268         for (int i = 0; i < listViewCounters.Items.Count; i++) {\r
269           tw.Write(listViewCounters.Items[i].SubItems[0].Text + "\t");\r
270           tw.WriteLine(listViewCounters.Items[i].SubItems[1].Text);\r
271         }\r
272       }\r
273       catch (IOException ex) {\r
274         MessageBox.Show(string.Format("There was an error while saving your results file. The results might not have been saved correctly.: {0}", ex.Message));\r
275       } \r
276       finally{\r
277         if (tw != null) tw.Close();\r
278       }\r
279     }\r
280 \r
281     #endregion\r
282 \r
283     class ListViewItemComparer : IComparer {\r
284       public ListViewItemComparer() {\r
285         this.col_ = 0;\r
286         this.order_ = SortOrder.Ascending;\r
287       }\r
288 \r
289       public ListViewItemComparer(int column, SortOrder order) {\r
290         this.col_ = column;\r
291         this.order_ = order;\r
292       }\r
293 \r
294       public int Compare(object x, object y) {\r
295         int return_value = -1;\r
296 \r
297         object x_tag = ((ListViewItem)x).SubItems[col_].Tag;\r
298         object y_tag = ((ListViewItem)y).SubItems[col_].Tag;\r
299 \r
300         if (Comparable(x_tag, y_tag))\r
301           return_value = ((IComparable)x_tag).CompareTo(y_tag);\r
302         else\r
303           return_value = String.Compare(((ListViewItem)x).SubItems[col_].Text,\r
304               ((ListViewItem)y).SubItems[col_].Text);\r
305 \r
306         if (order_ == SortOrder.Descending)\r
307           return_value *= -1;\r
308 \r
309         return return_value;\r
310       }\r
311 \r
312       #region Private Methods\r
313       private bool Comparable(object x, object y) {\r
314         if (x == null || y == null)\r
315           return false;\r
316 \r
317         return x is IComparable && y is IComparable;\r
318       }\r
319       #endregion\r
320 \r
321       #region Private Members\r
322       private int col_;\r
323       private SortOrder order_;\r
324       #endregion\r
325     }\r
326 \r
327     #region Private Members\r
328     private const string kStringAllProcesses = "All Processes";\r
329     private const string kStringProcess = "Process ";\r
330     private const int kPollInterval = 1000;  // 1 second\r
331     private const string kStatsTableName = "ChromeStats";\r
332     private StatsTable stats_table_;\r
333     private StatsTableCounters stats_counters_;\r
334     private Timer timer_;\r
335     private int filter_pid_;\r
336     private bool pause_updates_;\r
337     private int sort_column_ = -1;\r
338     #endregion\r
339 \r
340     #region Private Event Callbacks\r
341     private void openToolStripMenuItem_Click(object sender, EventArgs e)\r
342     {\r
343       OpenDialog dialog = new OpenDialog();\r
344       dialog.ShowDialog();\r
345 \r
346       CloseStatsFile();\r
347 \r
348       StatsTable table = new StatsTable();\r
349       bool rv = table.Open(dialog.FileName);\r
350       if (!rv)\r
351       {\r
352         MessageBox.Show("Could not open statsfile: " + dialog.FileName);\r
353       }\r
354       else\r
355       {\r
356         stats_table_ = table;\r
357       }\r
358     }\r
359 \r
360     private void closeToolStripMenuItem_Click(object sender, EventArgs e)\r
361     {\r
362       CloseStatsFile();\r
363     }\r
364 \r
365     private void quitToolStripMenuItem_Click(object sender, EventArgs e)\r
366     {\r
367       Application.Exit();\r
368     }\r
369     #endregion\r
370   }\r
371 \r
372   /// <summary>\r
373   /// Base class for counter list view items.\r
374   /// </summary>\r
375   internal class StatsCounterListViewItem : ListViewItem\r
376   {\r
377     /// <summary>\r
378     /// Create the ListViewItem\r
379     /// </summary>\r
380     /// <param name="text"></param>\r
381     public StatsCounterListViewItem(string text) : base(text) { }\r
382 \r
383     /// <summary>\r
384     /// Update the ListViewItem given a new counter value.\r
385     /// </summary>\r
386     /// <param name="counter"></param>\r
387     /// <param name="filter_pid"></param>\r
388     public virtual void Update(IStatsCounter counter, int filter_pid) { }\r
389 \r
390     /// <summary>\r
391     /// Set the background color based on the value\r
392     /// </summary>\r
393     /// <param name="value"></param>\r
394     protected void ColorItem(int value)\r
395     {\r
396       if (value < 0)\r
397         ForeColor = Color.Red;\r
398       else if (value > 0)\r
399         ForeColor = Color.DarkGreen;\r
400       else\r
401         ForeColor = Color.Black;\r
402     }\r
403 \r
404     /// <summary>\r
405     /// Create a new subitem with a zeroed Tag.\r
406     /// </summary>\r
407     /// <returns></returns>\r
408     protected ListViewSubItem NewSubItem()\r
409     {\r
410       ListViewSubItem item = new ListViewSubItem();\r
411       item.Tag = -1;  // Arbitrarily initialize to -1.\r
412       return item;\r
413     }\r
414 \r
415     /// <summary>\r
416     /// Set the value for a subitem.\r
417     /// </summary>\r
418     /// <param name="item"></param>\r
419     /// <param name="val"></param>\r
420     /// <returns>True if the value changed, false otherwise</returns>\r
421     protected bool SetSubItem(ListViewSubItem item, int val)\r
422     {\r
423       // The reason for doing this extra compare is because \r
424       // we introduce flicker if we unnecessarily update the \r
425       // subitems.  The UI is much less likely to cause you\r
426       // a seizure when we do this.\r
427       if (val != (int)item.Tag)\r
428       {\r
429         item.Text = val.ToString();\r
430         item.Tag = val;\r
431         return true;\r
432       }\r
433       return false;\r
434     }\r
435   }\r
436 \r
437   /// <summary>\r
438   /// A listview item which contains a rate.\r
439   /// </summary>\r
440   internal class RateListViewItem : StatsCounterListViewItem\r
441   {\r
442     public RateListViewItem(IStatsCounter ctr, int filter_pid) :\r
443       base(ctr.name)\r
444     {\r
445       StatsCounterRate rate = ctr as StatsCounterRate;\r
446       Name = rate.name;\r
447       SubItems.Add(NewSubItem());\r
448       SubItems.Add(NewSubItem());\r
449       SubItems.Add(NewSubItem());\r
450       Update(ctr, filter_pid);\r
451     }\r
452 \r
453     public override void Update(IStatsCounter counter, int filter_pid)\r
454     {\r
455       Debug.Assert(counter is StatsCounterRate);\r
456 \r
457       StatsCounterRate new_rate = counter as StatsCounterRate;\r
458       int new_count = new_rate.GetCount(filter_pid);\r
459       int new_time = new_rate.GetTime(filter_pid);\r
460       int old_avg = Tag != null ? (int)Tag : 0;\r
461       int new_avg = new_count > 0 ? (new_time / new_count) : 0;\r
462       int delta = new_avg - old_avg;\r
463 \r
464       SetSubItem(SubItems[column_count_index], new_count);\r
465       SetSubItem(SubItems[column_time_index], new_time);\r
466       if (SetSubItem(SubItems[column_avg_index], new_avg)) \r
467         ColorItem(delta);\r
468       Tag = new_avg;\r
469     }\r
470 \r
471     private const int column_count_index = 1;\r
472     private const int column_time_index = 2;\r
473     private const int column_avg_index = 3;\r
474   }\r
475 \r
476   /// <summary>\r
477   /// A listview item which contains a counter.\r
478   /// </summary>\r
479   internal class CounterListViewItem : StatsCounterListViewItem\r
480   {\r
481     public CounterListViewItem(IStatsCounter ctr, int filter_pid) :\r
482       base(ctr.name)\r
483     {\r
484       Name = ctr.name;\r
485       SubItems.Add(NewSubItem());\r
486       SubItems.Add(NewSubItem());\r
487       Update(ctr, filter_pid);\r
488     }\r
489 \r
490     public override void Update(IStatsCounter counter, int filter_pid) {\r
491       Debug.Assert(counter is StatsCounter || counter is StatsTimer);\r
492 \r
493       int new_value = 0;\r
494       if (counter is StatsCounter)\r
495         new_value = ((StatsCounter)counter).GetValue(filter_pid);\r
496       else if (counter is StatsTimer)\r
497         new_value = ((StatsTimer)counter).GetValue(filter_pid);\r
498 \r
499       int old_value = Tag != null ? (int)Tag : 0;\r
500       int delta = new_value - old_value;\r
501       SetSubItem(SubItems[column_value_index], new_value);\r
502       if (SetSubItem(SubItems[column_delta_index], delta))\r
503         ColorItem(delta);\r
504       Tag = new_value;\r
505     }\r
506 \r
507     private const int column_value_index = 1;\r
508     private const int column_delta_index = 2;\r
509   }\r
510 }\r