1 module dlangide.ui.dmdprofilerview; 2 3 import dlangui.widgets.layouts; 4 import dlangui.widgets.widget; 5 import dlangui.widgets.grid; 6 import dlangui.widgets.scroll; 7 import dlangui.widgets.controls; 8 import dlangide.ui.frame; 9 import dlangide.ui.commands; 10 import dlangui.core.i18n; 11 import dlangide.tools.d.dmdtrace; 12 13 class DMDProfilerView : WidgetGroupDefaultDrawing { 14 protected IDEFrame _frame; 15 protected DMDTraceLogParser _data; 16 protected TraceFunctionList _fullFunctionList; 17 this(string ID, IDEFrame frame, DMDTraceLogParser data) { 18 super(ID); 19 _frame = frame; 20 _data = data; 21 layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); 22 _fullFunctionList = new TraceFunctionList("FULL_FUNCTION_LIST", "All functions"d, _data.nodesByTotalTime, _data.ticks_per_second); // new TextWidget(null, "DMD profiler view"d); 23 addChild(_fullFunctionList); 24 } 25 /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). 26 override void layout(Rect rc) { 27 super.layout(rc); 28 applyMargins(rc); 29 applyPadding(rc); 30 Rect rc1 = rc; 31 rc1.right = rc1.left + rc.width / 2; 32 _fullFunctionList.layout(rc1); 33 } 34 /** 35 Measure widget according to desired width and height constraints. (Step 1 of two phase layout). 36 37 */ 38 override void measure(int parentWidth, int parentHeight) { 39 _fullFunctionList.measure(parentWidth, parentHeight); 40 measuredContent(parentWidth, parentHeight, _fullFunctionList.measuredWidth, _fullFunctionList.measuredHeight); 41 } 42 } 43 44 class TraceFuncionGrid : StringGridWidgetBase { 45 protected FunctionNode[] _list; 46 protected dstring[] _colTitles; 47 protected ulong _ticksPerSecond; 48 this(string ID, FunctionNode[] list, ulong ticks_per_second) { 49 super(ID); 50 _ticksPerSecond = ticks_per_second; 51 _list = list; 52 layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); 53 fullColumnOnLeft(false); 54 fullRowOnTop(false); 55 resize(4, cast(int)list.length); 56 setColTitle(0, "Function name"d); 57 setColTitle(1, "Called"d); 58 setColTitle(2, "F us"d); 59 setColTitle(3, "F+D us"d); 60 showRowHeaders = false; 61 rowSelect = true; 62 minVisibleRows = 10; 63 minVisibleCols = 4; 64 } 65 66 private dchar[128] _numberFormatBuf; 67 dstring formatNumber(ulong v, dchar[] buffer) { 68 dchar[64] buf; 69 int k = 0; 70 if (!v) { 71 buf[k++] = '0'; 72 } else { 73 while (v) { 74 buf[k++] = '0' + (cast(int)(v % 10)); 75 v /= 10; 76 } 77 } 78 // reverse order 79 for (int i = 0; i < k; i++) 80 buffer[i] = buf[k - i - 1]; 81 return cast(dstring)buffer[0..k]; 82 } 83 dstring formatDurationTicks(ulong n) { 84 ulong v = n * 1000000 / _ticksPerSecond; 85 return formatNumber(v, _numberFormatBuf[]); 86 } 87 88 /// get cell text 89 override dstring cellText(int col, int row) { 90 if (row < 0 || row >= _list.length) 91 return ""d; 92 FunctionNode entry = _list[row]; 93 switch (col) { 94 case 0: 95 string fn = entry.name; 96 if (fn.length > 256) 97 fn = fn[0..256] ~ "..."; 98 return fn.to!dstring; 99 case 1: 100 return formatNumber(entry.number_of_calls, _numberFormatBuf); 101 case 2: 102 return formatDurationTicks(entry.function_time); 103 case 3: 104 return formatDurationTicks(entry.function_and_descendant_time); 105 default: 106 return ""d; 107 } 108 } 109 /// set cell text 110 override StringGridWidgetBase setCellText(int col, int row, dstring text) { 111 // do nothing 112 return this; 113 } 114 /// returns row header title 115 override dstring rowTitle(int row) { 116 return ""d; 117 } 118 /// set row header title 119 override StringGridWidgetBase setRowTitle(int row, dstring title) { 120 return this; 121 } 122 123 /// returns row header title 124 override dstring colTitle(int col) { 125 return _colTitles[col]; 126 } 127 128 /// set col header title 129 override StringGridWidgetBase setColTitle(int col, dstring title) { 130 _colTitles[col] = title; 131 return this; 132 } 133 134 void autofit() { 135 autoFitColumnWidths(); 136 fillColumnWidth(0); 137 } 138 139 /// set new size 140 override void resize(int c, int r) { 141 if (c == cols && r == rows) 142 return; 143 int oldcols = cols; 144 int oldrows = rows; 145 super.resize(c, r); 146 _colTitles.length = c; 147 } 148 149 protected override Point measureCell(int x, int y) { 150 if (_customCellAdapter && _customCellAdapter.isCustomCell(x, y)) { 151 return _customCellAdapter.measureCell(x, y); 152 } 153 //Log.d("measureCell ", x, ", ", y); 154 FontRef fnt = font; 155 dstring txt; 156 if (x >= 0 && y >= 0) 157 txt = cellText(x, y); 158 else if (y < 0 && x >= 0) 159 txt = colTitle(x); 160 else if (y >= 0 && x < 0) 161 txt = rowTitle(y); 162 Point sz = fnt.textSize(txt); 163 if (sz.y < fnt.height) 164 sz.y = fnt.height; 165 return sz; 166 } 167 168 169 /// draw cell content 170 protected override void drawCell(DrawBuf buf, Rect rc, int col, int row) { 171 if (_customCellAdapter && _customCellAdapter.isCustomCell(col, row)) { 172 return _customCellAdapter.drawCell(buf, rc, col, row); 173 } 174 if (BACKEND_GUI) 175 rc.shrink(2, 1); 176 else 177 rc.right--; 178 FontRef fnt = font; 179 dstring txt = cellText(col, row); 180 Point sz = fnt.textSize(txt); 181 Align ha = Align.Right; 182 //if (sz.y < rc.height) 183 applyAlign(rc, sz, ha, Align.VCenter); 184 int offset = BACKEND_CONSOLE ? 0 : 1; 185 fnt.drawText(buf, rc.left + offset, rc.top + offset, txt, textColor); 186 } 187 188 /// draw cell content 189 protected override void drawHeaderCell(DrawBuf buf, Rect rc, int col, int row) { 190 if (BACKEND_GUI) 191 rc.shrink(2, 1); 192 else 193 rc.right--; 194 FontRef fnt = font; 195 dstring txt; 196 if (row < 0 && col >= 0) 197 txt = colTitle(col); 198 else if (row >= 0 && col < 0) 199 txt = rowTitle(row); 200 if (!txt.length) 201 return; 202 Point sz = fnt.textSize(txt); 203 Align ha = Align.Left; 204 if (col < 0) 205 ha = Align.Right; 206 //if (row < 0) 207 // ha = Align.HCenter; 208 applyAlign(rc, sz, ha, Align.VCenter); 209 int offset = BACKEND_CONSOLE ? 0 : 1; 210 uint cl = textColor; 211 cl = style.customColor("grid_cell_text_color_header", cl); 212 fnt.drawText(buf, rc.left + offset, rc.top + offset, txt, cl); 213 } 214 215 /// draw cell background 216 protected override void drawHeaderCellBackground(DrawBuf buf, Rect rc, int c, int r) { 217 bool selectedCol = (c == col) && !_rowSelect; 218 bool selectedRow = r == row; 219 bool selectedCell = selectedCol && selectedRow; 220 if (_rowSelect && selectedRow) 221 selectedCell = true; 222 if (!selectedCell && _multiSelect) { 223 selectedCell = Point(c, r) in _selection || (_rowSelect && Point(0, r) in _selection); 224 } 225 // draw header cell background 226 DrawableRef dw = c < 0 ? _cellRowHeaderBackgroundDrawable : _cellHeaderBackgroundDrawable; 227 uint cl = _cellHeaderBackgroundColor; 228 if (c >= 0 || r >= 0) { 229 if (c < 0 && selectedRow) { 230 cl = _cellHeaderSelectedBackgroundColor; 231 dw = _cellRowHeaderSelectedBackgroundDrawable; 232 } else if (r < 0 && selectedCol) { 233 cl = _cellHeaderSelectedBackgroundColor; 234 dw = _cellHeaderSelectedBackgroundDrawable; 235 } 236 } 237 if (!dw.isNull) 238 dw.drawTo(buf, rc); 239 else 240 buf.fillRect(rc, cl); 241 static if (BACKEND_GUI) { 242 uint borderColor = _cellHeaderBorderColor; 243 buf.drawLine(Point(rc.right - 1, rc.bottom), Point(rc.right - 1, rc.top), _cellHeaderBorderColor); // vertical 244 buf.drawLine(Point(rc.left, rc.bottom - 1), Point(rc.right - 1, rc.bottom - 1), _cellHeaderBorderColor); // horizontal 245 } 246 } 247 248 /// draw cell background 249 protected override void drawCellBackground(DrawBuf buf, Rect rc, int c, int r) { 250 bool selectedCol = c == col; 251 bool selectedRow = r == row; 252 bool selectedCell = selectedCol && selectedRow; 253 if (_rowSelect && selectedRow) 254 selectedCell = true; 255 if (!selectedCell && _multiSelect) { 256 selectedCell = Point(c, r) in _selection || (_rowSelect && Point(0, r) in _selection); 257 } 258 uint borderColor = _cellBorderColor; 259 if (c < fixedCols || r < fixedRows) { 260 // fixed cell background 261 buf.fillRect(rc, _fixedCellBackgroundColor); 262 borderColor = _fixedCellBorderColor; 263 } 264 static if (BACKEND_GUI) { 265 buf.drawLine(Point(rc.left, rc.bottom + 1), Point(rc.left, rc.top), borderColor); // vertical 266 buf.drawLine(Point(rc.left, rc.bottom - 1), Point(rc.right - 1, rc.bottom - 1), borderColor); // horizontal 267 } 268 if (selectedCell) { 269 static if (BACKEND_GUI) { 270 if (_rowSelect) 271 buf.drawFrame(rc, _selectionColorRowSelect, Rect(0,1,0,1), _cellBorderColor); 272 else 273 buf.drawFrame(rc, _selectionColor, Rect(1,1,1,1), _cellBorderColor); 274 } else { 275 if (_rowSelect) 276 buf.fillRect(rc, _selectionColorRowSelect); 277 else 278 buf.fillRect(rc, _selectionColor); 279 } 280 } 281 } 282 283 /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout). 284 override void layout(Rect rc) { 285 super.layout(rc); 286 autofit(); 287 } 288 } 289 290 class TraceFunctionList : VerticalLayout { 291 TraceFuncionGrid _grid; 292 293 this(string ID, dstring title, FunctionNode[] list, ulong ticks_per_second) { 294 super(ID); 295 addChild(new TextWidget("gridTitle", title).layoutWidth(FILL_PARENT)); 296 _grid = new TraceFuncionGrid("FUNCTION_LIST", list, ticks_per_second); 297 addChild(_grid); 298 layoutWidth(FILL_PARENT).layoutHeight(FILL_PARENT); 299 } 300 }