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.distributed; 17 18 import com.intellij.ui.AncestorListenerAdapter; 19 import com.intellij.ui.components.JBPanel; 20 import net.miginfocom.swing.MigLayout; 21 import ohos.devtools.views.distributed.bean.DistributedFuncBean; 22 import ohos.devtools.views.distributed.bean.DistributedParams; 23 import ohos.devtools.views.distributed.bean.DistributedThreadBean; 24 import ohos.devtools.views.distributed.component.DeviceExpandPanel; 25 import ohos.devtools.views.distributed.component.DistributedTracePanel; 26 import ohos.devtools.views.distributed.component.TraceFuncRow; 27 import ohos.devtools.views.distributed.util.DistributedCache; 28 import ohos.devtools.views.distributed.util.DistributedDB; 29 import ohos.devtools.views.trace.EventDispatcher; 30 import ohos.devtools.views.trace.ExpandPanel; 31 import ohos.devtools.views.trace.Sql; 32 import ohos.devtools.views.trace.Tip; 33 import ohos.devtools.views.trace.util.Utils; 34 35 import javax.swing.JLayeredPane; 36 import javax.swing.SwingUtilities; 37 import javax.swing.event.AncestorEvent; 38 import java.util.ArrayList; 39 import java.util.List; 40 import java.util.Objects; 41 import java.util.Optional; 42 import java.util.concurrent.CompletableFuture; 43 import java.util.stream.Collectors; 44 45 /** 46 * DistributedPanel 47 * 48 * @since 2021/7/6 15:36 49 */ 50 public class DistributedChartPanel extends JBPanel { 51 /** 52 * JLayeredPane layeredPane 53 */ 54 private JLayeredPane layeredPane; 55 private DistributedTracePanel tracePanel; 56 private Tip tip = Tip.getInstance(); 57 private DistributedParams params; 58 private JBPanel spacerPanel = new JBPanel(); 59 60 /** 61 * DistributedChartPanel 62 */ DistributedChartPanel()63 public DistributedChartPanel() { 64 setLayout(new MigLayout("insets 0")); 65 } 66 67 /** 68 * load by paramstest 69 * 70 * @param params params 71 */ load(DistributedParams params)72 public void load(DistributedParams params) { 73 this.params = params; 74 Utils.resetPool(); 75 recycleData(); 76 DistributedDB.setDbName(params.getPathA(), params.getPathB()); 77 DistributedDB.load(true); 78 initUI(); 79 EventDispatcher.addThreadRangeListener((startNS, endNS, threadIds) -> { 80 if (threadIds.isEmpty()) { 81 hideTab(); 82 } else { 83 Optional.ofNullable(DistributedPanel.getTab()).ifPresent(it -> { 84 displayTab(); 85 }); 86 } 87 }); 88 EventDispatcher.addClickListener(it -> { 89 if (it instanceof DistributedFuncBean) { 90 DistributedFuncBean func = (DistributedFuncBean) it; 91 Optional.ofNullable(DistributedPanel.getTab()).ifPresent(item -> { 92 displayTab(); 93 }); 94 } 95 }); 96 } 97 recycleData()98 private void recycleData() { 99 removeAll(); 100 EventDispatcher.clearData(); 101 DistributedTracePanel.CURRENT_SELECT_THREAD_IDS.clear(); 102 DistributedFuncBean.currentSelectedFunc = null; 103 DistributedCache.recycleData(); 104 } 105 initUI()106 private void initUI() { 107 DistributedCache.setDistribuetedParams(params); 108 CompletableFuture.runAsync(() -> { 109 DistributedDB.getInstance().queryA(Sql.DISTRIBUTED_QUERY_TOTAL_TIME, DistributedCache.DUR_A); 110 DistributedDB.getInstance().queryB(Sql.DISTRIBUTED_QUERY_TOTAL_TIME, DistributedCache.DUR_B); 111 if (DistributedCache.getDistribuetedParams().getOffsetA() != null) { 112 DistributedDB.getInstance().updateA(Sql.DISTRIBUTED_SET_TRACE_RANGE_START_TIME, 113 DistributedCache.getDistribuetedParams().getOffsetA()); 114 } 115 if (DistributedCache.getDistribuetedParams().getOffsetB() != null) { 116 DistributedDB.getInstance().updateB(Sql.DISTRIBUTED_SET_TRACE_RANGE_START_TIME, 117 DistributedCache.getDistribuetedParams().getOffsetB()); 118 } 119 if (!DistributedCache.DUR_A.isEmpty() && !DistributedCache.DUR_B.isEmpty()) { 120 Long totalA = DistributedCache.DUR_A.get(0).getTotal(); 121 Long totalB = DistributedCache.DUR_B.get(0).getTotal(); 122 DistributedTracePanel.setDURATION(Math.max(totalA, totalB)); 123 DistributedTracePanel.startNS = 0; 124 DistributedTracePanel.endNS = Math.max(totalA, totalB); 125 } 126 SwingUtilities.invokeLater(this::tracePanelInit); 127 }, Utils.getPool()).whenComplete((unused, throwable) -> { 128 if (Objects.nonNull(throwable)) { 129 throwable.printStackTrace(); 130 } 131 }); 132 } 133 tracePanelInit()134 private void tracePanelInit() { 135 setLayout(new MigLayout("insets 0")); 136 tracePanel = new DistributedTracePanel(); 137 insertDeviceA(); 138 insertDeviceB(); 139 tracePanel.getContentPanel().add(spacerPanel, "pushx,growx,h 200!"); 140 tracePanel.addAncestorListener(new AncestorListenerAdapter() { 141 @Override 142 public void ancestorAdded(AncestorEvent event) { 143 super.ancestorAdded(event); 144 layeredPane = DistributedChartPanel.this.getRootPane().getLayeredPane(); 145 SwingUtilities.invokeLater(() -> { 146 hideTab(); 147 tip.setJLayeredPane(layeredPane); 148 }); 149 } 150 151 @Override 152 public void ancestorRemoved(AncestorEvent event) { 153 super.ancestorRemoved(event); 154 hideTab(); 155 tip.hidden(); 156 } 157 }); 158 add(tracePanel, "push,grow"); 159 } 160 insertDeviceA()161 private void insertDeviceA() { 162 DistributedDB.getInstance() 163 .queryA(Sql.DISTRIBUTED_QUERY_THREADS_BY_PID, DistributedCache.THREADS_A, params.getProcessIdA()); 164 DistributedCache.setThreadNamesA(DistributedCache.THREADS_A.stream() 165 .collect(Collectors.toMap(th -> th.getTid(), th -> th.getName() == null ? "" : th.getName()))); 166 DeviceExpandPanel root = 167 new DeviceExpandPanel(params.getPkgNameA() + " (" + params.getDeviceNameA() + ")", "A"); 168 ExpandPanel panel = 169 new ExpandPanel("Process " + params.getProcessIdA() + " (" + DistributedCache.THREADS_A.size() + ")", 110); 170 for (DistributedThreadBean thread : DistributedCache.THREADS_A) { 171 TraceFuncRow<DistributedFuncBean> row = new TraceFuncRow<>(thread.getName(), thread.getTid()); 172 row.setRender((g2, data2) -> { 173 if (data2 != null) { 174 data2.stream().filter(item -> row.contains(item)).forEach(func -> { 175 func.setRect(row.getRectByNode(func, 1, row.getFuncHeight())); 176 func.draw(g2); 177 }); 178 } 179 }); 180 row.setSupplier(() -> { 181 List<DistributedFuncBean> funcs = new ArrayList<>() { 182 }; 183 DistributedDB.getInstance().queryA(Sql.DISTRIBUTED_GET_FUN_DATA_BY_TID, funcs, thread.getTid()); 184 funcs.forEach((item) -> { 185 item.setCurrentType(DistributedFuncBean.BeanDataType.TYPE_A); 186 DistributedCache.ID_FUNC_BEAN_MAP_A.put(item.getId(), item); 187 }); 188 DistributedCache.FUNC_MAP_A.put(thread.getTid(), funcs); 189 int maxDept = funcs.stream().mapToInt(DistributedFuncBean::getDepth).max().orElse(0) + 1; 190 int maxHeight = maxDept * row.getFuncHeight() + row.getFuncHeight(); 191 if (maxHeight < 30) { 192 maxHeight = 30; 193 } 194 row.setMaxDept(maxDept); 195 if (panel.getContent().getLayout() instanceof MigLayout) { 196 MigLayout migLayout = (MigLayout) panel.getContent().getLayout(); 197 migLayout.setComponentConstraints(row, "growx,pushx,h " + maxHeight + "!"); 198 } 199 row.updateUI(); 200 return funcs; 201 }); 202 panel.addTraceRow(row); 203 } 204 root.addRow(panel, "gapleft 5,pushx,growx"); 205 tracePanel.getContentPanel().add(root, "pushx,growx"); 206 } 207 insertDeviceB()208 private void insertDeviceB() { 209 DistributedDB.getInstance() 210 .queryB(Sql.DISTRIBUTED_QUERY_THREADS_BY_PID, DistributedCache.THREADS_B, params.getProcessIdB()); 211 DistributedCache.setThreadNamesB(DistributedCache.THREADS_B.stream() 212 .collect(Collectors.toMap(th -> th.getTid(), th -> th.getName() == null ? "" : th.getName()))); 213 DeviceExpandPanel root = 214 new DeviceExpandPanel(params.getPkgNameB() + " (" + params.getDeviceNameB() + ")", "B"); 215 ExpandPanel panel = 216 new ExpandPanel("Process " + params.getProcessIdB() + " (" + DistributedCache.THREADS_B.size() + ")", 110); 217 for (DistributedThreadBean thread : DistributedCache.THREADS_B) { 218 TraceFuncRow<DistributedFuncBean> row = new TraceFuncRow<>(thread.getName(), thread.getTid()); 219 row.setRender((g2, data2) -> { 220 if (data2 != null) { 221 data2.stream().filter(item -> row.contains(item)).forEach(func -> { 222 func.setRect(row.getRectByNode(func, 1, row.getFuncHeight())); 223 func.draw(g2); 224 }); 225 } 226 }); 227 row.setSupplier(() -> { 228 List<DistributedFuncBean> funcs = new ArrayList<>() { 229 }; 230 DistributedDB.getInstance().queryB(Sql.DISTRIBUTED_GET_FUN_DATA_BY_TID, funcs, thread.getTid()); 231 funcs.forEach((item) -> { 232 item.setCurrentType(DistributedFuncBean.BeanDataType.TYPE_B); 233 DistributedCache.ID_FUNC_BEAN_MAP_B.put(item.getId(), item); 234 }); 235 DistributedCache.FUNC_MAP_B.put(thread.getTid(), funcs); 236 int maxDept = funcs.stream().mapToInt(DistributedFuncBean::getDepth).max().orElse(0) + 1; 237 int maxHeight = maxDept * row.getFuncHeight() + row.getFuncHeight(); 238 if (maxHeight < 30) { 239 maxHeight = 30; 240 } 241 row.setMaxDept(maxDept); 242 if (panel.getContent().getLayout() instanceof MigLayout) { 243 MigLayout migLayout = (MigLayout) panel.getContent().getLayout(); 244 migLayout.setComponentConstraints(row, "growx,pushx,h " + maxHeight + "!"); 245 } 246 row.updateUI(); 247 return funcs; 248 }); 249 panel.addTraceRow(row); 250 } 251 root.addRow(panel, "gapleft 5,pushx,growx"); 252 tracePanel.getContentPanel().add(root, "pushx,growx"); 253 } 254 hideTab()255 private void hideTab() { 256 if (DistributedPanel.getTab() != null && layeredPane != null) { 257 if (DistributedFuncBean.currentSelectedFunc != null) { 258 DistributedFuncBean.currentSelectedFunc.setSelected(false); 259 DistributedFuncBean.currentSelectedFunc = null; 260 } 261 DistributedPanel.getTab().setVisible(false); 262 if (DistributedPanel.getSplitter() != null) { 263 DistributedPanel.getSplitter().setProportion(1.0f); 264 } 265 tracePanel.getTimeShaft().requestFocusInWindow(); 266 } 267 } 268 displayTab()269 private void displayTab() { 270 if (Objects.nonNull(DistributedPanel.getTab())) { 271 DistributedPanel.getTab().setVisible(true); 272 if (DistributedPanel.getSplitter() != null) { 273 DistributedPanel.getSplitter().setProportion(0.6f); 274 } 275 } 276 } 277 setSpacerPanelHeight(int height)278 private void setSpacerPanelHeight(int height) { 279 MigLayout layout = (MigLayout) tracePanel.getContentPanel().getLayout(); 280 layout.setComponentConstraints(spacerPanel, 281 "growx,pushx,h " + (height - DistributedPanel.getTab().getBarHeight()) + "!"); 282 spacerPanel.updateUI(); 283 } 284 } 285