1 /* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package ohos.devtools.views.layout.chartview.memory.javaagent; 17 18 import com.intellij.ui.HighlightableCellRenderer; 19 import com.intellij.ui.JBSplitter; 20 import com.intellij.ui.components.JBPanel; 21 import com.intellij.ui.treeStructure.treetable.ListTreeTableModelOnColumns; 22 import com.intellij.ui.treeStructure.treetable.TreeColumnInfo; 23 import com.intellij.util.ui.ColumnInfo; 24 import ohos.devtools.datasources.databases.databaseapi.DataBaseApi; 25 import ohos.devtools.datasources.utils.profilerlog.ProfilerLogManager; 26 import ohos.devtools.services.memory.agentbean.AgentHeapBean; 27 import ohos.devtools.services.memory.agentdao.ClassInfoManager; 28 import ohos.devtools.services.memory.agentdao.MemoryHeapManager; 29 import ohos.devtools.views.charts.model.ChartDataRange; 30 import ohos.devtools.views.charts.model.ChartStandard; 31 import ohos.devtools.views.common.treetable.ExpandTreeTable; 32 import ohos.devtools.views.common.treetable.TreeTableColumn; 33 import ohos.devtools.views.layout.chartview.ProfilerChartsView; 34 import ohos.devtools.views.layout.chartview.memory.MemoryItemView; 35 import org.apache.commons.lang3.StringUtils; 36 import org.apache.logging.log4j.LogManager; 37 import org.apache.logging.log4j.Logger; 38 39 import javax.swing.BoundedRangeModel; 40 import javax.swing.JLabel; 41 import javax.swing.JScrollBar; 42 import javax.swing.SortOrder; 43 import javax.swing.SwingWorker; 44 import javax.swing.table.DefaultTableCellRenderer; 45 import javax.swing.tree.DefaultMutableTreeNode; 46 import javax.swing.tree.TreePath; 47 import java.awt.BorderLayout; 48 import java.awt.event.MouseAdapter; 49 import java.awt.event.MouseEvent; 50 import java.awt.event.MouseMotionAdapter; 51 import java.util.ArrayList; 52 import java.util.List; 53 import java.util.Objects; 54 55 import static ohos.devtools.views.common.Constant.MEMORY_AGENT_INIT_COUNT; 56 57 /** 58 * MemoryAgentHeapInfoPanel 59 * 60 * @since : 2021/10/25 61 */ 62 public class MemoryAgentHeapInfoPanel extends JBPanel { 63 private static final Logger LOGGER = LogManager.getLogger(MemoryAgentHeapInfoPanel.class); 64 65 /** 66 * columns 67 */ 68 public final ColumnInfo[] columns = 69 new ColumnInfo[] {new TreeColumnInfo("Class Name"), new TreeTableColumn<>("Allocations", AgentHeapBean.class) { 70 @Override 71 public String getColumnValue(AgentHeapBean nodeData) { 72 return String.valueOf(nodeData.getAgentAllocationsCount()); 73 } 74 }, new TreeTableColumn<>("Deallocations", AgentHeapBean.class) { 75 @Override 76 public String getColumnValue(AgentHeapBean nodeData) { 77 return String.valueOf(nodeData.getAgentDeAllocationsCount()); 78 } 79 }, new TreeTableColumn<>("Total Count", AgentHeapBean.class) { 80 @Override 81 public String getColumnValue(AgentHeapBean nodeData) { 82 return String.valueOf(nodeData.getAgentTotalInstanceCount()); 83 } 84 }, new TreeTableColumn<>("Shallow Size", AgentHeapBean.class) { 85 @Override 86 public String getColumnValue(AgentHeapBean nodeData) { 87 return String.valueOf(nodeData.getAgentTotalshallowSize()); 88 } 89 }}; 90 91 /** 92 * allAgentDatas 93 */ 94 private List<AgentHeapBean> allAgentDatas; 95 96 /** 97 * lastDataNode 98 */ 99 private AgentHeapBean lastDataNode; 100 101 /** 102 * mouseMotionAdapter 103 */ 104 private MouseMotionAdapter mouseMotionAdapter; 105 106 private ExpandTreeTable treeTable; 107 108 /** 109 * mouseListener 110 */ 111 private MouseAdapter mouseListener; 112 113 /** 114 * MemoryAgentHeapInfoPanel 115 * 116 * @param memoryItemView memoryItemView 117 * @param sessionId long 118 * @param chartName String 119 */ MemoryAgentHeapInfoPanel(MemoryItemView memoryItemView, long sessionId, String chartName)120 public MemoryAgentHeapInfoPanel(MemoryItemView memoryItemView, long sessionId, String chartName) { 121 if (ProfilerLogManager.isInfoEnabled()) { 122 LOGGER.info("MemoryAgentHeapInfoPanel"); 123 } 124 setLayout(new BorderLayout()); 125 SwingWorker<ExpandTreeTable, Object> task = new SwingWorker<>() { 126 /** 127 * doInBackground 128 * 129 * @return JTreeTable 130 * @throws Exception Exception 131 */ 132 @Override 133 protected ExpandTreeTable doInBackground() { 134 return createTable(memoryItemView, sessionId, chartName); 135 } 136 137 /** 138 * done 139 */ 140 @Override 141 protected void done() { 142 if (Objects.nonNull(treeTable)) { 143 add(treeTable); 144 } 145 } 146 }; 147 task.execute(); 148 } 149 150 /** 151 * Copy list according to subscript 152 * 153 * @param dataList dataList 154 * @param startIndex startIndex 155 * @param endIndex endIndex 156 * @return list 157 */ listCopy(List<AgentHeapBean> dataList, int startIndex, int endIndex)158 public List<AgentHeapBean> listCopy(List<AgentHeapBean> dataList, int startIndex, int endIndex) { 159 if (ProfilerLogManager.isInfoEnabled()) { 160 LOGGER.info("listCopy"); 161 } 162 List list = new ArrayList(); 163 for (int index = startIndex + 1; index < endIndex; index++) { 164 if (index < dataList.size()) { 165 AgentHeapBean agentHeapBean = dataList.get(index); 166 if (agentHeapBean != null) { 167 list.add(agentHeapBean); 168 } 169 } 170 } 171 return list; 172 } 173 174 /** 175 * createTreeTable 176 * 177 * @param memoryItemView memoryItemView 178 * @param sessionId long 179 * @param chartName String 180 * @return ExpandTreeTable 181 */ createTable(MemoryItemView memoryItemView, long sessionId, String chartName)182 public ExpandTreeTable createTable(MemoryItemView memoryItemView, long sessionId, String chartName) { 183 if (ProfilerLogManager.isInfoEnabled()) { 184 LOGGER.info("createTable"); 185 } 186 DefaultMutableTreeNode root = initData(sessionId, chartName); 187 ListTreeTableModelOnColumns tableModelOnColumns = new ListTreeTableModelOnColumns(root, columns); 188 ExpandTreeTable treeTables = new ExpandTreeTable(tableModelOnColumns); 189 DefaultTableCellRenderer defaultTableCellRenderer = new DefaultTableCellRenderer(); 190 defaultTableCellRenderer.setHorizontalAlignment(JLabel.RIGHT); 191 treeTables.getTable().setDefaultRenderer(Object.class, defaultTableCellRenderer); 192 JScrollBar tableVerticalScrollBar1 = treeTables.getVerticalScrollBar(); 193 getMouseMotionAdapter(tableModelOnColumns, treeTables); 194 tableVerticalScrollBar1.addMouseMotionListener(mouseMotionAdapter); 195 AgentTreeTableRowSorter sorter = new AgentTreeTableRowSorter(treeTables.getTable().getModel()); 196 sorter.setListener((columnIndex, sortOrder) -> { 197 if (columnIndex <= 0 || columnIndex > columns.length) { 198 return; 199 } 200 if (sortOrder == SortOrder.ASCENDING) { 201 AgentTreeTableRowSorter 202 .sortDescTree(MemoryAgentHeapInfoPanel.this, columns[columnIndex].getName(), tableModelOnColumns); 203 } else { 204 AgentTreeTableRowSorter 205 .sortTree(MemoryAgentHeapInfoPanel.this, columns[columnIndex].getName(), tableModelOnColumns); 206 } 207 tableModelOnColumns.reload(); 208 }); 209 treeTables.getTree().setRootVisible(true); 210 treeTables.getTree().setExpandsSelectedPaths(true); 211 treeTables.getTable().setRowSorter(sorter); 212 treeTables.getTree().setCellRenderer(new HighlightableCellRenderer()); 213 treeTables.getTree().getExpandableItemsHandler().setEnabled(true); 214 mouseListener = getTreeTableMouseListener(memoryItemView, sessionId, chartName); 215 treeTables.getTable().addMouseListener(mouseListener); 216 treeTables.getTree().addMouseListener(mouseListener); 217 treeTable = treeTables; 218 return treeTables; 219 } 220 getTreeTableMouseListener(MemoryItemView memoryItemView, long sessionId, String chartName)221 private MouseAdapter getTreeTableMouseListener(MemoryItemView memoryItemView, long sessionId, String chartName) { 222 return new MouseAdapter() { 223 /** 224 * mouseClicked 225 * 226 * @param mouseEvent mouseEvent 227 */ 228 @Override 229 public void mouseClicked(MouseEvent mouseEvent) { 230 if (mouseEvent.getClickCount() == 1) { 231 int selectedRow = treeTable.getTable().getSelectedRow(); 232 TreePath treePath = treeTable.getTree().getPathForRow(selectedRow); 233 if (treePath == null) { 234 return; 235 } 236 Object rowNode = treePath.getLastPathComponent(); 237 if (rowNode instanceof DefaultMutableTreeNode) { 238 DefaultMutableTreeNode rowData = (DefaultMutableTreeNode) rowNode; 239 Object dataNode = rowData.getUserObject(); 240 if (dataNode instanceof AgentHeapBean) { 241 String className = ((AgentHeapBean) dataNode).getAgentClazzName(); 242 int cid = new ClassInfoManager().getClassIdByClassName(className); 243 // Need to be obtained from the first-level interface 244 JBPanel instanceViewPanel = 245 memoryItemView.setSecondLevelTreeTable(sessionId, cid, className, chartName); 246 memoryItemView.instanceAndDetailSplitter.setFirstComponent(instanceViewPanel); 247 memoryItemView.instanceAndDetailSplitter.setSecondComponent(new JBSplitter(false, 1)); 248 if (memoryItemView.instanceViewTable != null) { 249 memoryItemView.instanceViewTable.addMouseListener(new MouseAdapter() { 250 /** 251 * mouseClicked 252 * 253 * @param mouseEvent mouseEvent 254 */ 255 @Override 256 public void mouseClicked(MouseEvent mouseEvent) { 257 int selectedRow = memoryItemView.instanceViewTable.getSelectedRow(); 258 if (selectedRow < 0) { 259 return; 260 } 261 Object id = memoryItemView.instanceViewTable.getValueAt(selectedRow, 3); 262 if (id instanceof Integer) { 263 Integer instanceId = (Integer) id; 264 JBPanel callStack = 265 memoryItemView.setThirdLevelTreeTable(sessionId, instanceId, className); 266 memoryItemView.instanceAndDetailSplitter.setSecondComponent(callStack); 267 } 268 } 269 }); 270 } 271 memoryItemView.agentHeapSplitter 272 .setSecondComponent(memoryItemView.instanceAndDetailSplitter); 273 } 274 } 275 } 276 } 277 }; 278 } 279 280 /** 281 * getMouseMotionAdapter 282 * 283 * @param tableModelOnColumns tableModelOnColumns 284 * @param treeTables treeTables 285 */ 286 private void getMouseMotionAdapter(ListTreeTableModelOnColumns tableModelOnColumns, ExpandTreeTable treeTables) { 287 mouseMotionAdapter = new MouseMotionAdapter() { 288 @Override 289 public void mouseDragged(MouseEvent mouseEvent) { 290 JScrollBar jScrollBar = null; 291 Object sourceObject = mouseEvent.getSource(); 292 if (sourceObject instanceof JScrollBar) { 293 jScrollBar = (JScrollBar) sourceObject; 294 BoundedRangeModel model = jScrollBar.getModel(); 295 if (model.getExtent() + model.getValue() == model.getMaximum()) { 296 ListTreeTableModelOnColumns model1 = null; 297 Object modelObject = treeTables.getTree().getModel(); 298 if (modelObject instanceof ListTreeTableModelOnColumns) { 299 model1 = (ListTreeTableModelOnColumns) modelObject; 300 DefaultMutableTreeNode root1 = null; 301 Object rootObject = model1.getRoot(); 302 if (rootObject instanceof DefaultMutableTreeNode) { 303 root1 = (DefaultMutableTreeNode) rootObject; 304 int index = allAgentDatas.indexOf(lastDataNode); 305 List<AgentHeapBean> list = listCopy(allAgentDatas, index, index + 20); 306 for (AgentHeapBean agentDataNode : list) { 307 DefaultMutableTreeNode defaultMutableTreeNode = 308 new DefaultMutableTreeNode(agentDataNode); 309 tableModelOnColumns 310 .insertNodeInto(defaultMutableTreeNode, root1, root1.getChildCount()); 311 lastDataNode = agentDataNode; 312 } 313 } 314 } 315 } 316 } 317 } 318 }; 319 } 320 321 /** 322 * init treeTable Data 323 * 324 * @param sessionId long 325 * @param chartName String 326 * @return DefaultMutableTreeNode 327 */ 328 public DefaultMutableTreeNode initData(long sessionId, String chartName) { 329 if (ProfilerLogManager.isInfoEnabled()) { 330 LOGGER.info("initData"); 331 } 332 ChartStandard standard = ProfilerChartsView.sessionMap.get(sessionId).getPublisher().getStandard(); 333 MemoryHeapManager memoryHeapManager = new MemoryHeapManager(); 334 ChartDataRange selectedRang = standard.getSelectedRange(chartName); 335 String db = DataBaseApi.getInstance().checkTableRegister("ClassInfo"); 336 if (selectedRang == null || StringUtils.isBlank(db)) { 337 return new DefaultMutableTreeNode(); 338 } 339 long firstTime = standard.getFirstTimestamp(); 340 long endTimeNew = firstTime + selectedRang.getEndTime(); 341 allAgentDatas = memoryHeapManager.getMemoryHeapInfos(sessionId, 0L, endTimeNew); 342 AgentHeapBean agentHeapBean = new AgentHeapBean(); 343 DefaultMutableTreeNode appNode = new DefaultMutableTreeNode(); 344 int totalAllocations = 0; 345 int totalDeallocations = 0; 346 int totalTotalCount = 0; 347 long totalShallowSize = 0L; 348 if (!allAgentDatas.isEmpty()) { 349 for (int index = 0; index < MEMORY_AGENT_INIT_COUNT; index++) { 350 AgentHeapBean node = allAgentDatas.get(index); 351 if (index == MEMORY_AGENT_INIT_COUNT - 1) { 352 lastDataNode = node; 353 } 354 appNode.add(new DefaultMutableTreeNode(node)); 355 } 356 } 357 for (AgentHeapBean meInfo : allAgentDatas) { 358 totalAllocations = totalAllocations + meInfo.getAgentAllocationsCount(); 359 totalDeallocations = totalDeallocations + meInfo.getAgentDeAllocationsCount(); 360 totalTotalCount = totalTotalCount + meInfo.getAgentTotalInstanceCount(); 361 totalShallowSize = totalShallowSize + meInfo.getAgentTotalshallowSize(); 362 } 363 agentHeapBean.setAgentClazzName("app heap"); 364 agentHeapBean.setAgentAllocationsCount(totalAllocations); 365 agentHeapBean.setAgentDeAllocationsCount(totalDeallocations); 366 agentHeapBean.setAgentTotalInstanceCount(totalTotalCount); 367 agentHeapBean.setAgentTotalshallowSize(totalShallowSize); 368 appNode.setUserObject(agentHeapBean); 369 return appNode; 370 } 371 372 public ExpandTreeTable getTreeTable() { 373 return treeTable; 374 } 375 376 public List<AgentHeapBean> getAllAgentDatas() { 377 return allAgentDatas; 378 } 379 380 public void setAllAgentDatas(List<AgentHeapBean> allAgentDatas) { 381 this.allAgentDatas = allAgentDatas; 382 } 383 384 public AgentHeapBean getLastDataNode() { 385 return lastDataNode; 386 } 387 388 public void setLastDataNode(AgentHeapBean lastDataNode) { 389 this.lastDataNode = lastDataNode; 390 } 391 392 public MouseMotionAdapter getMouseMotionAdapter() { 393 return mouseMotionAdapter; 394 } 395 396 public void setMouseMotionAdapter(MouseMotionAdapter mouseMotionAdapter) { 397 this.mouseMotionAdapter = mouseMotionAdapter; 398 } 399 } 400