1b65280ffSSui Chen// This file deals with preprocessing the parsed DBus timeline data. 2b65280ffSSui Chen// Data and Timestamps are separate b/c dbus-pcap does not include 3b65280ffSSui Chen// timestamps in JSON output so we need to export both formats 4b65280ffSSui Chen// (JSON and text) 5b65280ffSSui Chenvar Data_DBus = []; 6b65280ffSSui Chenvar Timestamps_DBus = []; 7b65280ffSSui Chen 8b65280ffSSui Chen// Main view object 9b65280ffSSui Chenvar dbus_timeline_view = new DBusTimelineView(); 10b65280ffSSui Chenvar sensors_timeline_view = new DBusTimelineView(); // Same DBusTimelineView type, just that it will have only sensor propertieschanged events 11b65280ffSSui Chen 12b65280ffSSui Chen// group-by condition changes 13b65280ffSSui Chen{ 14b65280ffSSui Chen const tags = [ 15b65280ffSSui Chen 'dbus_column1', 'dbus_column2', 'dbus_column3', 'dbus_column4', 16b65280ffSSui Chen 'dbus_column5', 'dbus_column6', 'dbus_column7' 17b65280ffSSui Chen ]; 18b65280ffSSui Chen for (let i = 0; i < 7; i++) { 19b65280ffSSui Chen document.getElementById(tags[i]).addEventListener( 20b65280ffSSui Chen 'click', OnGroupByConditionChanged_DBus); 21b65280ffSSui Chen } 22b65280ffSSui Chen} 23b65280ffSSui Chen 24b65280ffSSui Chen// Called from renderer.Render() 25b65280ffSSui Chenfunction draw_timeline_sensors(ctx) { 26b65280ffSSui Chen sensors_timeline_view.Render(ctx); 27b65280ffSSui Chen} 28b65280ffSSui Chen 29b65280ffSSui Chen// Called from renderer.Render() 30b65280ffSSui Chenfunction draw_timeline_dbus(ctx) { 31b65280ffSSui Chen dbus_timeline_view.Render(ctx); 32b65280ffSSui Chen} 33b65280ffSSui Chen 34b65280ffSSui Chenlet Canvas_DBus = document.getElementById('my_canvas_dbus'); 35b65280ffSSui Chen 36b65280ffSSui Chenconst IDXES = { 37b65280ffSSui Chen 'Type': 0, 38b65280ffSSui Chen 'Timestamp': 1, 39b65280ffSSui Chen 'Serial': 2, 40b65280ffSSui Chen 'Sender': 3, 41b65280ffSSui Chen 'Destination': 4, 42b65280ffSSui Chen 'Path': 5, 43b65280ffSSui Chen 'Interface': 6, 44b65280ffSSui Chen 'Member': 7 45b65280ffSSui Chen}; 46b65280ffSSui Chen 47b65280ffSSui Chen// This "group" is based on the content of the DBus 48b65280ffSSui Chen// It is independent of the "group_by" of the meta-data (sender/destination/ 49b65280ffSSui Chen// path/interface/member) of a DBus message 50b65280ffSSui Chen// 51b65280ffSSui Chen// Input is processed message and some basic statistics needed for categorizing 52b65280ffSSui Chen// 53b65280ffSSui Chenconst DBusMessageContentKey = function(msg, cxn_occ) { 54b65280ffSSui Chen let ret = undefined; 55b65280ffSSui Chen const type = msg[IDXES["Type"]]; 56b65280ffSSui Chen const dest = msg[IDXES["Destination"]]; 57b65280ffSSui Chen const path = msg[IDXES["Path"]]; 58b65280ffSSui Chen const iface = msg[IDXES["Interface"]]; 59b65280ffSSui Chen const member = msg[IDXES["Member"]]; 60b65280ffSSui Chen const sender = msg[IDXES["Sender"]]; 61b65280ffSSui Chen 62b65280ffSSui Chen if (sender == "s" || sender == "sss") { 63b65280ffSSui Chen console.log(msg) 64b65280ffSSui Chen } 65b65280ffSSui Chen 66b65280ffSSui Chen if (type == "sig") { 67b65280ffSSui Chen if (path.indexOf("/xyz/openbmc_project/sensors/") != -1 && 68b65280ffSSui Chen iface == "org.freedesktop.DBus.Properties" && 69b65280ffSSui Chen member == "PropertiesChanged") { 70b65280ffSSui Chen ret = "Sensor PropertiesChanged Signals"; 71b65280ffSSui Chen } 72b65280ffSSui Chen } else if (type == "mc") { 73b65280ffSSui Chen if (dest == "xyz.openbmc_project.Ipmi.Host" && 74b65280ffSSui Chen path == "/xyz/openbmc_project/Ipmi" && 75b65280ffSSui Chen iface == "xyz.openbmc_project.Ipmi.Server" && 76b65280ffSSui Chen member == "execute") { 77b65280ffSSui Chen ret = "IPMI Daemon"; 78b65280ffSSui Chen } 79b65280ffSSui Chen } 80b65280ffSSui Chen 81b65280ffSSui Chen if (ret == undefined && cxn_occ[sender] <= 10) { 82b65280ffSSui Chen ret = "Total 10 messages or less" 83b65280ffSSui Chen } 84b65280ffSSui Chen 85b65280ffSSui Chen if (ret == undefined && type == "mc") { 86b65280ffSSui Chen if (path.indexOf("/xyz/openbmc_project/sensors/") == 0 && 87b65280ffSSui Chen iface == "org.freedesktop.DBus.Properties" && 88b65280ffSSui Chen (member.startsWith("Get") || member.startsWith("Set"))) { 89b65280ffSSui Chen ret = "Sensor Get/Set"; 90b65280ffSSui Chen } 91b65280ffSSui Chen } 92b65280ffSSui Chen 93b65280ffSSui Chen if (ret == undefined) { 94b65280ffSSui Chen ret = "Uncategorized"; 95b65280ffSSui Chen } 96b65280ffSSui Chen 97b65280ffSSui Chen return ret; 98b65280ffSSui Chen} 99b65280ffSSui Chen 100b65280ffSSui Chenfunction Group_DBus(preprocessed, group_by) { 101b65280ffSSui Chen let grouped = {}; // [content key][sort key] -> packet 102b65280ffSSui Chen 103b65280ffSSui Chen let cxn_occ = {}; // How many times have a specific service appeared? 104b65280ffSSui Chen preprocessed.forEach((pp) => { 105b65280ffSSui Chen const cxn = pp[IDXES["Sender"]]; 106b65280ffSSui Chen if (cxn_occ[cxn] == undefined) { 107b65280ffSSui Chen cxn_occ[cxn] = 0; 108b65280ffSSui Chen } 109b65280ffSSui Chen cxn_occ[cxn]++; 110b65280ffSSui Chen }); 111b65280ffSSui Chen 112b65280ffSSui Chen for (var n = 0; n < preprocessed.length; n++) { 113b65280ffSSui Chen var key = ''; 114b65280ffSSui Chen for (var i = 0; i < group_by.length; i++) { 115b65280ffSSui Chen if (i > 0) key += ' '; 116b65280ffSSui Chen key += ('' + preprocessed[n][IDXES[group_by[i]]]); 117b65280ffSSui Chen } 118b65280ffSSui Chen 119b65280ffSSui Chen // "Content Key" is displayed on the "Column Headers" 120b65280ffSSui Chen const content_group = DBusMessageContentKey(preprocessed[n], cxn_occ); 121b65280ffSSui Chen 122b65280ffSSui Chen // Initialize the "Collapsed" array here 123b65280ffSSui Chen // TODO: this should ideally not be specific to the dbus_interface_view instance 124b65280ffSSui Chen if (dbus_timeline_view.HeaderCollapsed[content_group] == undefined) { 125b65280ffSSui Chen dbus_timeline_view.HeaderCollapsed[content_group] = false; // Not collapsed by default 126b65280ffSSui Chen } 127b65280ffSSui Chen 128b65280ffSSui Chen if (grouped[content_group] == undefined) { 129b65280ffSSui Chen grouped[content_group] = []; 130b65280ffSSui Chen } 131b65280ffSSui Chen let grouped1 = grouped[content_group]; 132b65280ffSSui Chen 133b65280ffSSui Chen if (grouped1[key] == undefined) grouped1[key] = []; 134b65280ffSSui Chen grouped1[key].push(preprocessed[n]); 135b65280ffSSui Chen } 136b65280ffSSui Chen return grouped; 137b65280ffSSui Chen} 138b65280ffSSui Chen 139b65280ffSSui Chenfunction OnGroupByConditionChanged_DBus() { 140b65280ffSSui Chen var tags = [ 141b65280ffSSui Chen 'dbus_column1', 'dbus_column2', 'dbus_column3', 'dbus_column4', 142b65280ffSSui Chen 'dbus_column5', 'dbus_column6', 'dbus_column7' 143b65280ffSSui Chen ]; 144b65280ffSSui Chen const v = dbus_timeline_view; 145b65280ffSSui Chen v.GroupBy = []; 146b65280ffSSui Chen v.GroupByStr = ''; 147b65280ffSSui Chen for (let i = 0; i < tags.length; i++) { 148b65280ffSSui Chen let cb = document.getElementById(tags[i]); 149b65280ffSSui Chen if (cb.checked) { 150b65280ffSSui Chen v.GroupBy.push(cb.value); 151b65280ffSSui Chen if (v.GroupByStr.length > 0) { 152b65280ffSSui Chen v.GroupByStr += ', '; 153b65280ffSSui Chen } 154b65280ffSSui Chen v.GroupByStr += cb.value; 155b65280ffSSui Chen } 156b65280ffSSui Chen } 157b65280ffSSui Chen let preproc = Preprocess_DBusPcap( 158b65280ffSSui Chen Data_DBus, Timestamps_DBus); // should be from dbus_pcap 159b65280ffSSui Chen let grouped = Group_DBus(preproc, v.GroupBy); 160b65280ffSSui Chen GenerateTimeLine_DBus(grouped); 161b65280ffSSui Chen dbus_timeline_view.IsCanvasDirty = true; 162b65280ffSSui Chen} 163b65280ffSSui Chen 164b65280ffSSui Chen// Todo: put g_StartingSec somewhere that's common between sensors and non-sensors 165b65280ffSSui Chenfunction GenerateTimeLine_DBus(grouped) { 166b65280ffSSui Chen let intervals = []; 167b65280ffSSui Chen let titles = []; 168b65280ffSSui Chen g_StartingSec = undefined; 169b65280ffSSui Chen 170b65280ffSSui Chen // First, turn "content keys" into headers in the flattened layout 171b65280ffSSui Chen const content_keys = Object.keys(grouped); 172b65280ffSSui Chen 173b65280ffSSui Chen const keys = Object.keys(grouped); 174b65280ffSSui Chen let sortedKeys = keys.slice(); 175b65280ffSSui Chen 176b65280ffSSui Chen let interval_idx = 0; // The overall index into the intervals array 177b65280ffSSui Chen 178b65280ffSSui Chen for (let x=0; x<content_keys.length; x++) { 179b65280ffSSui Chen const content_key = content_keys[x]; 180b65280ffSSui Chen // Per-content key 181b65280ffSSui Chen const grouped1 = grouped[content_key]; 182b65280ffSSui Chen const keys1 = Object.keys(grouped1); 183b65280ffSSui Chen 184b65280ffSSui Chen let the_header = { "header":true, "title":content_key, "intervals_idxes":[] }; 185b65280ffSSui Chen titles.push(the_header); 186b65280ffSSui Chen // TODO: this currently depends on the dbus_timeline_view instance 187b65280ffSSui Chen const collapsed = dbus_timeline_view.HeaderCollapsed[content_key]; 188b65280ffSSui Chen 189b65280ffSSui Chen for (let i = 0; i < keys1.length; i++) { 190b65280ffSSui Chen // The Title array controls which lines are drawn. If we con't push the header 191b65280ffSSui Chen // it will not be drawn (thus giving a "collapsed" visual effect.) 192b65280ffSSui Chen if (!collapsed) { 193b65280ffSSui Chen titles.push({ "header":false, "title":keys1[i], "intervals_idxes":[interval_idx] }); 194b65280ffSSui Chen } 195b65280ffSSui Chen 196b65280ffSSui Chen 197b65280ffSSui Chen line = []; 198b65280ffSSui Chen for (let j = 0; j < grouped1[keys1[i]].length; j++) { 199b65280ffSSui Chen let entry = grouped1[keys1[i]][j]; 200b65280ffSSui Chen let t0 = parseFloat(entry[1]) / 1000.0; 201b65280ffSSui Chen let t1 = parseFloat(entry[8]) / 1000.0; 202b65280ffSSui Chen 203b65280ffSSui Chen // Modify time shift delta if IPMI dataset is loaded first 204b65280ffSSui Chen if (g_StartingSec == undefined) { 205b65280ffSSui Chen g_StartingSec = t0; 206b65280ffSSui Chen } 207b65280ffSSui Chen g_StartingSec = Math.min(g_StartingSec, t0); 208b65280ffSSui Chen const outcome = entry[9]; 209b65280ffSSui Chen line.push([t0, t1, entry, outcome, 0]); 210b65280ffSSui Chen } 211b65280ffSSui Chen 212b65280ffSSui Chen the_header.intervals_idxes.push(interval_idx); // Keep the indices into the intervals array for use in rendering 213b65280ffSSui Chen intervals.push(line); 214b65280ffSSui Chen interval_idx ++; 215b65280ffSSui Chen } 216b65280ffSSui Chen 217b65280ffSSui Chen // Compute a set of "merged intervals" for each content_key 218b65280ffSSui Chen let rise_fall_edges = []; 219b65280ffSSui Chen the_header.intervals_idxes.forEach((i) => { 220b65280ffSSui Chen intervals[i].forEach((t0t1) => { 221*e8c12087SSui Chen if (t0t1[0] <= t0t1[1]) { // For errored-out method calls, the end time will be set to a value smaller than the start time 222b65280ffSSui Chen rise_fall_edges.push([t0t1[0], 0]); // 0 is a rising edge 223b65280ffSSui Chen rise_fall_edges.push([t0t1[1], 1]); // 1 is a falling edge 224b65280ffSSui Chen } 225b65280ffSSui Chen }) 226b65280ffSSui Chen }); 227b65280ffSSui Chen 228b65280ffSSui Chen let merged_intervals = [], 229b65280ffSSui Chen current_interval = [undefined, undefined, 0]; // start, end, weight 230b65280ffSSui Chen rise_fall_edges.sort(); 231b65280ffSSui Chen let i = 0, level = 0; 232b65280ffSSui Chen while (i<rise_fall_edges.length) { 233b65280ffSSui Chen let timestamp = rise_fall_edges[i][0]; 234b65280ffSSui Chen while (i < rise_fall_edges.length && timestamp == rise_fall_edges[i][0]) { 235b65280ffSSui Chen switch (rise_fall_edges[i][1]) { 236b65280ffSSui Chen case 0: { // rising edge 237b65280ffSSui Chen if (level == 0) { 238b65280ffSSui Chen current_interval[0] = timestamp; 239b65280ffSSui Chen current_interval[2] ++; 240b65280ffSSui Chen } 241b65280ffSSui Chen level ++; 242b65280ffSSui Chen break; 243b65280ffSSui Chen } 244b65280ffSSui Chen case 1: { // falling edge 245b65280ffSSui Chen level --; 246b65280ffSSui Chen if (level == 0) { 247b65280ffSSui Chen current_interval[1] = timestamp; 248b65280ffSSui Chen merged_intervals.push(current_interval); 249b65280ffSSui Chen current_interval = [undefined, undefined, 0]; 250b65280ffSSui Chen } 251b65280ffSSui Chen break; 252b65280ffSSui Chen } 253b65280ffSSui Chen } 254b65280ffSSui Chen i++; 255b65280ffSSui Chen } 256b65280ffSSui Chen } 257b65280ffSSui Chen the_header.merged_intervals = merged_intervals; 258b65280ffSSui Chen } 259b65280ffSSui Chen 260b65280ffSSui Chen // Time shift 261b65280ffSSui Chen for (let i = 0; i < intervals.length; i++) { 262b65280ffSSui Chen for (let j = 0; j < intervals[i].length; j++) { 263b65280ffSSui Chen let x = intervals[i][j]; 264b65280ffSSui Chen x[0] -= g_StartingSec; 265b65280ffSSui Chen x[1] -= g_StartingSec; 266b65280ffSSui Chen } 267b65280ffSSui Chen } 268b65280ffSSui Chen // merged intervals should be time-shifted as well 269b65280ffSSui Chen titles.forEach((t) => { 270b65280ffSSui Chen if (t.header == true) { 271b65280ffSSui Chen t.merged_intervals.forEach((mi) => { 272b65280ffSSui Chen mi[0] -= g_StartingSec; 273b65280ffSSui Chen mi[1] -= g_StartingSec; 274b65280ffSSui Chen }) 275b65280ffSSui Chen } 276b65280ffSSui Chen }) 277b65280ffSSui Chen 278b65280ffSSui Chen dbus_timeline_view.Intervals = intervals.slice(); 279b65280ffSSui Chen dbus_timeline_view.Titles = titles.slice(); 280b65280ffSSui Chen dbus_timeline_view.LayoutForOverlappingIntervals(); 281b65280ffSSui Chen} 282b65280ffSSui Chen 283b65280ffSSui ChenCanvas_DBus.onmousemove = 284b65280ffSSui Chen function(event) { 285b65280ffSSui Chen const v = dbus_timeline_view; 286b65280ffSSui Chen v.MouseState.x = event.pageX - this.offsetLeft; 287b65280ffSSui Chen v.MouseState.y = event.pageY - this.offsetTop; 288b65280ffSSui Chen if (v.MouseState.pressed == true && 289b65280ffSSui Chen v.MouseState.hoveredSide == 'timeline') { // Update highlighted area 290b65280ffSSui Chen v.HighlightedRegion.t1 = v.MouseXToTimestamp(v.MouseState.x); 291b65280ffSSui Chen } 292b65280ffSSui Chen v.OnMouseMove(); 293b65280ffSSui Chen v.IsCanvasDirty = true; 294b65280ffSSui Chen 295b65280ffSSui Chen v.linked_views.forEach(function(u) { 296b65280ffSSui Chen u.MouseState.x = event.pageX - Canvas_DBus.offsetLeft; 297b65280ffSSui Chen u.MouseState.y = undefined; // Do not highlight any entry or the horizontal scroll bars 298b65280ffSSui Chen if (u.MouseState.pressed == true && 299b65280ffSSui Chen v.MouseState.hoveredSide == 'timeline') { // Update highlighted area 300b65280ffSSui Chen u.HighlightedRegion.t1 = u.MouseXToTimestamp(u.MouseState.x); 301b65280ffSSui Chen } 302b65280ffSSui Chen u.OnMouseMove(); 303b65280ffSSui Chen u.IsCanvasDirty = true; 304b65280ffSSui Chen }); 305b65280ffSSui Chen} 306b65280ffSSui Chen 307b65280ffSSui ChenCanvas_DBus.onmousedown = function(event) { 308b65280ffSSui Chen if (event.button == 0) { 309b65280ffSSui Chen dbus_timeline_view.OnMouseDown(); 310b65280ffSSui Chen } 311b65280ffSSui Chen}; 312b65280ffSSui Chen 313b65280ffSSui ChenCanvas_DBus.onmouseup = 314b65280ffSSui Chen function(event) { 315b65280ffSSui Chen if (event.button == 0) { 316b65280ffSSui Chen dbus_timeline_view.OnMouseUp(); 317b65280ffSSui Chen } 318b65280ffSSui Chen} 319b65280ffSSui Chen 320b65280ffSSui ChenCanvas_DBus.onmouseleave = 321b65280ffSSui Chen function(event) { 322b65280ffSSui Chen dbus_timeline_view.OnMouseLeave(); 323b65280ffSSui Chen} 324b65280ffSSui Chen 325b65280ffSSui ChenCanvas_DBus.onwheel = function(event) { 326b65280ffSSui Chen dbus_timeline_view.OnMouseWheel(event); 327b65280ffSSui Chen} 328