Console.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. Ext.define('PageAnalyzer.Console', {
  2. extend: 'Ext.panel.Panel',
  3. requires: [
  4. 'Ext.chart.*',
  5. 'Ext.grid.Panel',
  6. 'Ext.grid.feature.Grouping',
  7. 'Ext.layout.container.Border',
  8. 'PageAnalyzer.models.BasicTimeData'
  9. ],
  10. layout: 'border',
  11. border: false,
  12. initComponent: function () {
  13. var me = this;
  14. me.addEvents('rawdataupdate');
  15. me.pathTpl = new Ext.XTemplate('{test} ({env} - {build})');
  16. me.samples = [];
  17. me.store = Ext.create('Ext.data.Store', {
  18. model: 'PageAnalyzer.models.BasicTimeData',
  19. sorters: [{ property: 'avgTime', direction: 'DESC' }],
  20. groupField: 'path'
  21. });
  22. me.detailStore = Ext.create('Ext.data.Store', {
  23. model: 'PageAnalyzer.models.BasicTimeData',
  24. sorters: { property: 'avgTime', direction: 'DESC' }
  25. });
  26. me.singleSampleStore = Ext.create('Ext.data.Store', {
  27. model: 'PageAnalyzer.models.BasicTimeData'
  28. });
  29. me.items = [
  30. {
  31. region: 'north',
  32. title: 'Trend',
  33. itemId: 'trendPanel',
  34. layout: 'fit',
  35. split: true,
  36. collapsible: true,
  37. collapsed: false,
  38. flex: 4,
  39. items: []
  40. },
  41. {
  42. region: 'center',
  43. title: 'Data',
  44. flex: 4,
  45. layout: 'border',
  46. border: false,
  47. items: [
  48. {
  49. region: 'center',
  50. xtype: 'tabpanel',
  51. tabPosition: 'bottom',
  52. flex: 5,
  53. items: [
  54. me.makeDataGrid({
  55. title: 'Grid',
  56. border: false
  57. }),
  58. {
  59. region: 'east',
  60. title: 'Raw',
  61. layout: 'fit',
  62. border: false,
  63. tbar: [
  64. {
  65. text: 'Load',
  66. handler: me.onUpdateFromRawData,
  67. scope: me
  68. }
  69. ],
  70. items: [
  71. {
  72. xtype: 'textarea',
  73. style: 'margin:0',
  74. itemId: 'rawData',
  75. emptyText: 'Raw data goes here...',
  76. selectOnFocus: true
  77. }
  78. ]
  79. },
  80. {
  81. title: 'Accumulators',
  82. xtype: 'textarea',
  83. style: 'margin:0',
  84. itemId: 'accumulatorCfg'
  85. }
  86. ]
  87. },
  88. me.makeDetailsChart({ region: 'east' })
  89. ]
  90. }
  91. ];
  92. me.callParent();
  93. },
  94. addSample: function (perfData) {
  95. var me = this,
  96. last = perfData;
  97. if (Ext.isArray(perfData)) {
  98. me.samples.push.apply(me.samples, perfData);
  99. last = last[last.length-1];
  100. } else {
  101. // perfData = { env: '..', test: '..', build: '..', data: Ext.Perf.getData() }
  102. me.samples.push(perfData);
  103. }
  104. me.update();
  105. var rec = me.store.findRecord('path', me.makePath(last));
  106. me.select(rec);
  107. },
  108. clearSamples: function() {
  109. var me = this;
  110. me.samples.length = 0;
  111. me.update();
  112. },
  113. makeDataGrid: function (config) {
  114. var me = this;
  115. return Ext.apply({
  116. xtype: 'grid',
  117. store: me.store,
  118. itemId: 'dataGrid',
  119. flex: 5,
  120. features: [
  121. {
  122. ftype:'grouping',
  123. hideGroupedHeader: true
  124. }
  125. ],
  126. columns: [
  127. { text: 'Environment', dataIndex: 'environment', hidden: true },
  128. { text: 'Build', dataIndex: 'build', hidden: true },
  129. { text: 'Test', dataIndex: 'test', hidden: true },
  130. { text: 'Path', dataIndex: 'path', sortable: true },
  131. { text: 'Name', dataIndex: 'measure', sortable: true },
  132. { text: 'Time', dataIndex: 'avgTime', sortable: true },
  133. { text: 'Time/Call', dataIndex: 'avgTimePerCall', sortable: true },
  134. { text: 'Samples', dataIndex: 'numSamples', sortable: true },
  135. { text: 'Min Calls', dataIndex: 'minCalls', sortable: true },
  136. { text: 'Max Calls', dataIndex: 'maxCalls', sortable: true }
  137. ],
  138. listeners: {
  139. selectionchange: function (model, selection) {
  140. me.onSelect(selection[0]);
  141. }
  142. }
  143. }, config);
  144. },
  145. makePath: function (perfData) {
  146. return this.pathTpl.apply(perfData);
  147. },
  148. makeDetailsChart: function (config) {
  149. var me = this;
  150. return Ext.apply({
  151. xtype: 'panel',
  152. title: 'Details',
  153. layout: 'fit',
  154. flex: 3,
  155. split: true,
  156. collapsible: true,
  157. preventHeader: true,
  158. items: [{
  159. xtype: 'chart',
  160. store: me.detailStore,
  161. itemId: 'measuresPieChart',
  162. theme: 'Base:gradients',
  163. series: [{
  164. type: 'pie',
  165. field: 'avgTime',
  166. label: {
  167. field: 'measure',
  168. display: 'rotate',
  169. font: '12px Arial'
  170. }
  171. }]
  172. }]
  173. }, config);
  174. },
  175. makeTrendChart: function () {
  176. var me = this,
  177. panel = me.down('#trendPanel'),
  178. builds = {},
  179. trendData = [],
  180. fields = [],
  181. measures = {},
  182. measureNames = [],
  183. modelName,
  184. chart;
  185. panel.removeAll();
  186. chart = {
  187. xtype: 'chart',
  188. style: 'background:#fff',
  189. animate: false,
  190. shadow: true,
  191. flex: 5,
  192. theme: 'Category1',
  193. legend: {
  194. position: 'right'
  195. },
  196. axes: [{
  197. type: 'Numeric',
  198. minimum: 0,
  199. position: 'left',
  200. fields: [],
  201. title: 'Time (ms)',
  202. minorTickSteps: 1,
  203. grid: {
  204. odd: {
  205. opacity: 1,
  206. fill: '#ddd',
  207. stroke: '#bbb',
  208. 'stroke-width': 0.5
  209. }
  210. }
  211. }, {
  212. type: 'Category',
  213. position: 'bottom',
  214. fields: ['build'],
  215. title: 'Build'
  216. }],
  217. series: []
  218. };
  219. me.store.each(function (r) {
  220. var rd = r.data;
  221. var build = builds[rd.build];
  222. if (!build) {
  223. builds[rd.build] = build = { build: rd.build };
  224. trendData.push(build);
  225. }
  226. build[rd.measure] = rd.avgTime;
  227. if (rd.measure in measures) {
  228. return;
  229. }
  230. fields.push(measures[rd.measure] = { name: rd.measure, type: 'float' });
  231. measureNames.push(rd.measure);
  232. chart.series.push({
  233. type: 'line',
  234. highlight: {
  235. size: 7,
  236. radius: 7
  237. },
  238. axis: 'left',
  239. xField: 'build',
  240. yField: rd.measure,
  241. markerConfig: {
  242. type: 'circle',
  243. size: 4,
  244. radius: 4,
  245. 'stroke-width': 0
  246. }
  247. });
  248. });
  249. chart.axes[0].fields = measureNames;
  250. measureNames.sort();
  251. var name = 'Trend_' + measureNames.join('$');
  252. name = name.replace(/\./g, '_');
  253. modelName = 'PageAnalyzer.models.' + name;
  254. var mfields = [{
  255. name: 'build',
  256. type: 'int'
  257. }];
  258. fields.push({name: 'build', type: 'int'});
  259. if (!PageAnalyzer.models[name]) {
  260. Ext.define(modelName, {
  261. extend: 'Ext.data.Model',
  262. fields: fields
  263. });
  264. }
  265. chart.store = Ext.create('Ext.data.Store', {
  266. model: modelName,
  267. sorters: { property: 'build', direction: 'ASC' }
  268. });
  269. if (trendData.length == 1) {
  270. trendData.unshift({
  271. build: '0',
  272. avgTime: null
  273. });
  274. }
  275. chart.store.loadData(trendData);
  276. chart.store.sort();
  277. panel.add(chart);
  278. },
  279. onSelect: function (rec) {
  280. var me = this,
  281. records = [],
  282. store = me.detailStore;
  283. if (rec) {
  284. me.store.each(function (r) {
  285. if (r.data.path == rec.data.path) {
  286. records.push(r.copy());
  287. }
  288. });
  289. }
  290. store.removeAll();
  291. if (records.length) {
  292. store.add(records);
  293. store.sort();
  294. }
  295. },
  296. onUpdateFromRawData: function () {
  297. var me = this,
  298. rawData = me.down('#rawData').getValue();
  299. me.samples = Ext.decode(rawData);
  300. me.update();
  301. },
  302. select: function (rec) {
  303. if (rec) {
  304. var me = this,
  305. grid = me.down('#dataGrid');
  306. grid.getSelectionModel().select(rec);
  307. }
  308. },
  309. update: function () {
  310. var me = this,
  311. map = {}, // map[env+test+build][measure] = record
  312. json = Ext.encode(me.samples),
  313. key,
  314. measures,
  315. measure,
  316. records = [];
  317. me.down('#rawData').setValue(json);
  318. me.fireEvent('rawdataupdate', me, json, me.samples);
  319. Ext.each(me.samples, function (perfData) {
  320. key = me.makePath(perfData);
  321. measures = map[key] || (map[key] = {});
  322. Ext.Object.each(perfData.data, function (name, stats) {
  323. measure = measures[name];
  324. if (!measure) {
  325. measures[name] = measure = new PageAnalyzer.models.BasicTimeData({
  326. environment: perfData.env,
  327. build: perfData.build,
  328. test: perfData.test,
  329. path: key,
  330. measure: name
  331. });
  332. }
  333. records.push(measure);
  334. measure.addSample(stats.pure.sum, stats.count);
  335. });
  336. });
  337. me.store.removeAll();
  338. me.store.add(records);
  339. me.store.sort();
  340. me.makeTrendChart();
  341. },
  342. setAccumulators: function (cfg) {
  343. var me = this,
  344. accData = Ext.JSON.encodeValue(cfg, '\n ');
  345. me.down('#accumulatorCfg').setValue(accData);
  346. },
  347. getAccumulators: function () {
  348. var me = this,
  349. accData = me.down('#accumulatorCfg').getValue();
  350. if(!accData || accData == '')
  351. return null;
  352. return Ext.decode(accData, true);
  353. }
  354. });