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.trace.component; 17 18 import com.intellij.ui.AncestorListenerAdapter; 19 import com.intellij.ui.components.JBPanel; 20 import com.intellij.ui.components.JBScrollPane; 21 import net.miginfocom.swing.MigLayout; 22 import ohos.devtools.views.trace.Sql; 23 import ohos.devtools.views.trace.bean.AsyncEvent; 24 import ohos.devtools.views.trace.bean.BinderArg; 25 import ohos.devtools.views.trace.bean.Clock; 26 import ohos.devtools.views.trace.bean.ClockData; 27 import ohos.devtools.views.trace.bean.Cpu; 28 import ohos.devtools.views.trace.bean.CpuData; 29 import ohos.devtools.views.trace.bean.CpuFreqData; 30 import ohos.devtools.views.trace.bean.CpuFreqMax; 31 import ohos.devtools.views.trace.bean.CpuMax; 32 import ohos.devtools.views.trace.bean.Duration; 33 import ohos.devtools.views.trace.bean.FlagBean; 34 import ohos.devtools.views.trace.bean.FunctionBean; 35 import ohos.devtools.views.trace.bean.Process; 36 import ohos.devtools.views.trace.bean.ProcessMem; 37 import ohos.devtools.views.trace.bean.ProcessMemData; 38 import ohos.devtools.views.trace.bean.ThreadData; 39 import ohos.devtools.views.trace.bean.WakeupBean; 40 import ohos.devtools.views.trace.bean.WakeupTime; 41 import ohos.devtools.views.trace.fragment.AbstractDataFragment; 42 import ohos.devtools.views.trace.fragment.AsyncEventDataFragment; 43 import ohos.devtools.views.trace.fragment.ClockDataFragment; 44 import ohos.devtools.views.trace.fragment.ClockFolderFragment; 45 import ohos.devtools.views.trace.fragment.CpuDataFragment; 46 import ohos.devtools.views.trace.fragment.CpuFreqDataFragment; 47 import ohos.devtools.views.trace.fragment.FunctionDataFragment; 48 import ohos.devtools.views.trace.fragment.MemDataFragment; 49 import ohos.devtools.views.trace.fragment.ProcessDataFragment; 50 import ohos.devtools.views.trace.fragment.ThreadDataFragment; 51 import ohos.devtools.views.trace.listener.IFlagListener; 52 import ohos.devtools.views.trace.util.Db; 53 import ohos.devtools.views.trace.util.TimeUtils; 54 import ohos.devtools.views.trace.util.Utils; 55 import org.apache.commons.compress.utils.Lists; 56 57 import javax.swing.JOptionPane; 58 import javax.swing.SwingUtilities; 59 import javax.swing.event.AncestorEvent; 60 import java.awt.Cursor; 61 import java.awt.Point; 62 import java.awt.Rectangle; 63 import java.awt.event.ComponentAdapter; 64 import java.awt.event.ComponentEvent; 65 import java.awt.event.KeyEvent; 66 import java.awt.event.KeyListener; 67 import java.awt.event.MouseEvent; 68 import java.awt.event.MouseListener; 69 import java.awt.event.MouseMotionListener; 70 import java.awt.event.MouseWheelEvent; 71 import java.awt.event.MouseWheelListener; 72 import java.util.ArrayList; 73 import java.util.List; 74 import java.util.Map; 75 import java.util.Objects; 76 import java.util.Optional; 77 import java.util.concurrent.CompletableFuture; 78 import java.util.concurrent.ConcurrentHashMap; 79 import java.util.function.Function; 80 import java.util.function.Predicate; 81 import java.util.stream.Collectors; 82 83 import static java.awt.event.KeyEvent.VK_A; 84 import static java.awt.event.KeyEvent.VK_CONTROL; 85 import static java.awt.event.KeyEvent.VK_D; 86 import static java.awt.event.KeyEvent.VK_F; 87 import static java.awt.event.KeyEvent.VK_S; 88 import static java.awt.event.KeyEvent.VK_SHIFT; 89 import static java.awt.event.KeyEvent.VK_W; 90 91 /** 92 * Analysis component 93 * 94 * @since 2021/04/20 12:24 95 */ 96 public final class AnalystPanel extends JBPanel 97 implements MouseWheelListener, KeyListener, MouseListener, MouseMotionListener { 98 /** 99 * rect clicked 100 */ 101 public static boolean clicked = false; 102 103 /** 104 * cpu click listener 105 */ 106 public static ICpuDataClick iCpuDataClick; 107 108 /** 109 * thread click listener 110 */ 111 public static IThreadDataClick iThreadDataClick; 112 113 /** 114 * function click listener 115 */ 116 public static IFunctionDataClick iFunctionDataClick; 117 118 /** 119 * function click listener 120 */ 121 private static IAsyncFunctionDataClick iAsyncFunctionDataClick; 122 123 /** 124 * clock data click listener 125 */ 126 private static IClockDataClick iClockDataClick; 127 128 /** 129 * mem data click listener 130 */ 131 private static IMemDataClick iMemDataClick; 132 133 /** 134 * flag click listener 135 */ 136 private static IFlagClick iFlagClick; 137 138 /** 139 * duration 140 */ 141 private static long DURATION = 10_000_000_000L; 142 143 /** 144 * cpu data list 145 */ 146 private static List<List<CpuData>> cpuList; 147 148 /** 149 * cpu freg data list 150 */ 151 private static List<List<CpuFreqData>> cpuFreqList; 152 153 /** 154 * thread data list 155 */ 156 private static List<ThreadData> threadsList; 157 158 /** 159 * cpu count 160 */ 161 private static int cpuNum; 162 163 /** 164 * bottom tab 165 */ 166 private TabPanel tab; 167 private final JBScrollPane scrollPane = new JBScrollPane(); 168 private final int defaultFragmentHeight = 40; 169 private final double defaultScale = 0.1D; 170 private ContentPanel contentPanel; 171 private TimeViewPort viewport; 172 private double wheelSize; 173 private double rangeNs; 174 private double lefPercent; 175 private double rightPercent; 176 private long startNS; 177 private boolean isUserInteraction; 178 private Cursor wCursor = new Cursor(Cursor.W_RESIZE_CURSOR); 179 private Cursor eCursor = new Cursor(Cursor.E_RESIZE_CURSOR); 180 private Cursor handCursor = new Cursor(Cursor.HAND_CURSOR); 181 private Cursor defaultCursor = new Cursor(Cursor.DEFAULT_CURSOR); 182 private TabLogTable tabLogTable = new TabLogTable(); 183 184 /** 185 * Constructor 186 */ AnalystPanel()187 public AnalystPanel() { 188 setLayout(new MigLayout("insets 0", "[grow,fill]", "[grow,fill]")); 189 viewport = new TimeViewPort(height -> viewport.setBorder(null), (sn, en) -> { 190 /** 191 * When the time axis range changes, 192 * the contentPanel is notified that all data is refreshed according to the time axis 193 */ 194 contentPanel.rangeChange(sn, en); 195 tabLogTable.rangeChange(sn, en); 196 }); 197 setBorder(null); 198 contentPanel = new ContentPanel(this); 199 contentPanel.setBorder(null); 200 viewport.setView(contentPanel); 201 scrollPane.setViewport(viewport); 202 scrollPane.setBorder(null); 203 addAncestorListener(new AncestorListenerAdapter() { 204 @Override 205 public void ancestorAdded(AncestorEvent event) { 206 super.ancestorAdded(event); 207 contentPanel.requestFocusInWindow(); 208 } 209 210 @Override 211 public void ancestorRemoved(AncestorEvent event) { 212 super.ancestorRemoved(event); 213 if (Objects.nonNull(tab)) { 214 tab.hidden(); 215 } 216 } 217 }); 218 this.addComponentListener(new ComponentAdapter() { 219 @Override 220 public void componentResized(ComponentEvent event) { 221 super.componentResized(event); 222 viewport.setRootHeight(getHeight()); 223 contentPanel.repaint(); 224 } 225 }); 226 add(scrollPane); 227 contentPanel.setFocusable(true); 228 contentPanel.addMouseMotionListener(this); 229 contentPanel.addMouseListener(this); 230 contentPanel.addKeyListener(this); 231 iCpuDataClick = cpu -> clickCpuData(cpu); 232 iThreadDataClick = thread -> clickThreadData(thread); 233 iFunctionDataClick = fun -> clickFunctionData(fun); 234 iClockDataClick = clock -> clickClockData(clock); 235 iFlagClick = flag -> clickTimeFlag(flag); 236 iAsyncFunctionDataClick = data -> clickAsyncFunctionData(data); 237 iMemDataClick = mem -> clickMemData(mem); 238 } 239 distinctByKey(Function<? super T, ?> keyExtractor)240 static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) { 241 Map<Object, Boolean> seen = new ConcurrentHashMap<>(); 242 return obj -> seen.putIfAbsent(keyExtractor.apply(obj), Boolean.TRUE) == null; 243 } 244 245 /** 246 * set tab 247 * 248 * @param tab tab 249 */ setTab(final TabPanel tab)250 public void setTab(final TabPanel tab) { 251 this.tab = tab; 252 } 253 254 /** 255 * add cpu data list 256 * 257 * @param list source 258 */ addCpuList(final List<List<CpuData>> list)259 public void addCpuList(final List<List<CpuData>> list) { 260 if (list == null) { 261 return; 262 } 263 cpuList = list; 264 cpuNum = list.size(); 265 for (int index = 0; index < list.size(); index++) { 266 contentPanel.addDataFragment(new CpuDataFragment(contentPanel, index, null)); 267 } 268 } 269 270 /** 271 * add cpu freg data list 272 * 273 * @param list source 274 * @param cpuMaxFreq cpu size 275 */ addCpuFreqList(final List<List<CpuFreqData>> list, final CpuFreqMax cpuMaxFreq)276 public void addCpuFreqList(final List<List<CpuFreqData>> list, final CpuFreqMax cpuMaxFreq) { 277 cpuFreqList = list; 278 for (int index = 0; index < list.size(); index++) { 279 List<CpuFreqData> dataList = list.get(index); 280 281 // Fill in the duration field in FreqData and calculate based on the start time of the next node 282 for (int idx = 0, len = dataList.size(); idx < len; idx++) { 283 CpuFreqData cpuGraph = dataList.get(idx); 284 if (idx == len - 1) { 285 cpuGraph.setDuration(AnalystPanel.DURATION - cpuGraph.getStartTime()); 286 } else { 287 cpuGraph.setDuration(dataList.get(idx + 1).getStartTime() - cpuGraph.getStartTime()); 288 } 289 } 290 contentPanel.addDataFragment( 291 new CpuFreqDataFragment(contentPanel, "Cpu " + index + " Frequency", cpuMaxFreq, dataList)); 292 } 293 } 294 295 /** 296 * add thread data list 297 * 298 * @param list thread list 299 * @param processMem process list 300 * @param asyncEvents asyncEvents 301 */ addThreadsList(final List<ThreadData> list, final List<ProcessMem> processMem, List<AsyncEvent> asyncEvents)302 public void addThreadsList(final List<ThreadData> list, final List<ProcessMem> processMem, 303 List<AsyncEvent> asyncEvents) { 304 /* 305 * If the list has no data (obtained by memory sorting), 306 * then directly query the process and thread tables to find the data 307 */ 308 if (list.isEmpty()) { 309 Db.getInstance().query(Sql.SYS_QUERY_PROCESS_THREADS_NORDER, list); 310 } 311 threadsList = list; 312 List<Process> processes = new ArrayList<>() { 313 }; 314 Db.getInstance().query(Sql.SYS_QUERY_PROCESS, processes); 315 if (processes.isEmpty()) { 316 Db.getInstance().query(Sql.SYS_QUERY_PROCESS_NORDER, processes); 317 } 318 processes.stream().filter(it -> it.getPid() != 0).forEach(process -> { 319 ProcessDataFragment processDataFragment = new ProcessDataFragment(contentPanel, process); 320 contentPanel.addDataFragment(processDataFragment); 321 processMem.stream().filter(mem -> mem.getPid() == process.getPid()).forEach(mem -> { 322 MemDataFragment fgr = new MemDataFragment(contentPanel, mem); 323 fgr.defaultHeight = defaultFragmentHeight; 324 fgr.parentUuid = processDataFragment.uuid; 325 fgr.visible = false; 326 contentPanel.addDataFragment(fgr); 327 }); 328 asyncEvents.stream().filter(it -> it.getPid().equals(process.getPid())) 329 .filter(distinctByKey(it -> it.getName())).forEach(it -> { 330 List<AsyncEvent> collect = asyncEvents.stream() 331 .filter(wt -> wt.getPid().equals(it.getPid()) && wt.getName().equals(it.getName())) 332 .collect(Collectors.toList()); 333 AsyncEventDataFragment fgr = new AsyncEventDataFragment(contentPanel, it, collect); 334 int maxHeight = (collect.stream().mapToInt(bean -> bean.getDepth()).max().getAsInt() + 1) * 20; 335 fgr.defaultHeight = maxHeight + 20; 336 fgr.parentUuid = processDataFragment.uuid; 337 fgr.visible = false; 338 contentPanel.addDataFragment(fgr); 339 }); 340 List<ThreadData> collect = list.stream().filter( 341 threadData -> threadData.getPid() == process.getPid() && threadData.getTid() != 0 342 && threadData.getThreadName() != null).collect(Collectors.toList()); 343 for (ThreadData data : collect) { 344 ThreadDataFragment fgr = new ThreadDataFragment(contentPanel, data); 345 fgr.defaultHeight = defaultFragmentHeight; 346 fgr.parentUuid = processDataFragment.uuid; 347 fgr.visible = false; 348 contentPanel.addDataFragment(fgr); 349 } 350 }); 351 // If you use the memory method to find the data, you need to execute the following code 352 if (!list.isEmpty()) { 353 addThreadsList2(list); 354 } 355 } 356 addThreadsList2(List<ThreadData> list)357 private void addThreadsList2(List<ThreadData> list) { 358 list.stream().filter(data -> data.getProcessName() == null || data.getProcessName().isEmpty()) 359 .forEach(threadData -> { 360 Process process = new Process(); 361 process.setPid(threadData.getTid()); 362 process.setName(threadData.getThreadName()); 363 ProcessDataFragment processDataFragment = new ProcessDataFragment(contentPanel, process); 364 contentPanel.addDataFragment(processDataFragment); 365 if (process.getName() == null) { 366 process.setName("Process"); 367 } 368 if (!process.getName().startsWith("swapper") && process.getPid() != 0) { 369 ThreadDataFragment fgr = new ThreadDataFragment(contentPanel, threadData); 370 fgr.defaultHeight = defaultFragmentHeight; 371 fgr.parentUuid = processDataFragment.uuid; 372 fgr.visible = false; 373 contentPanel.addDataFragment(fgr); 374 } 375 }); 376 } 377 recycle()378 private void recycle() { 379 Utils.resetPool(); 380 if (cpuList != null) { 381 cpuList.forEach(List::clear); 382 cpuList.clear(); 383 } 384 if (cpuFreqList != null) { 385 cpuFreqList.forEach(List::clear); 386 cpuFreqList.clear(); 387 } 388 if (threadsList != null) { 389 threadsList.clear(); 390 } 391 } 392 393 /** 394 * load database 395 * 396 * @param name db name 397 * @param isLocal is local db 398 */ load(final String name, final boolean isLocal)399 public void load(final String name, final boolean isLocal) { 400 recycle(); 401 Db.setDbName(name); 402 Db.load(isLocal); 403 tab.hidden(); 404 CompletableFuture.runAsync(() -> { 405 loadDur(); 406 List<List<CpuData>> list = loadCpuData(); 407 List<List<CpuFreqData>> freqList = loadCpuFreqData(); 408 // Add the memory information of the process 409 List<ProcessMem> processMem = new ArrayList<>() { 410 }; 411 Db.getInstance().query(Sql.SYS_GET_PROCESS_MEM, processMem); 412 List<AsyncEvent> asyncEvents = new ArrayList<>() { 413 }; 414 Db.getInstance().query(Sql.SYS_GET_ASYNC_EVENTS, asyncEvents); 415 // Add thread information 416 List<ThreadData> processThreads = new ArrayList<>() { 417 }; 418 Db.getInstance().query(Sql.SYS_QUERY_PROCESS_THREADS, processThreads); 419 List<CpuFreqMax> cpuFreqMaxList = new ArrayList<>() { 420 }; 421 Db.getInstance().query(Sql.SYS_QUERY_CPU_MAX_FREQ, cpuFreqMaxList); 422 SwingUtilities.invokeLater(() -> { 423 viewport.recycle(); 424 viewport.rulerFragment.setRange(0, AnalystPanel.DURATION, 0); 425 viewport.rulerFragment.recycle(); 426 viewport.cpuFragment.reloadData(); 427 contentPanel.recycle(); 428 addCpuList(list); 429 if (cpuFreqMaxList.size() > 0) { 430 addCpuFreqList(freqList, cpuFreqMaxList.get(0).math()); 431 } 432 ArrayList<Clock> clocks = new ArrayList<>() { 433 }; 434 Db.getInstance().query(Sql.SYS_QUERY_CLOCK_LIST, clocks); 435 addClock(clocks); 436 addThreadsList(processThreads, processMem, asyncEvents); // The memory information of the process and 437 // The thread information of the process is displayed together 438 // load logs 439 tab.removeAll(); 440 tab.display(); 441 tab.add("Logs", tabLogTable); 442 tab.hideInBottom(); 443 tabLogTable.query(true); 444 contentPanel.refresh(); 445 }); 446 }, Utils.getPool()).whenComplete((unused, throwable) -> { 447 if (Objects.nonNull(throwable)) { 448 throwable.printStackTrace(); 449 } 450 }); 451 } 452 addClock(ArrayList<Clock> clocks)453 private void addClock(ArrayList<Clock> clocks) { 454 if (!clocks.isEmpty()) { 455 Clock screenState = new Clock(); 456 screenState.setName("ScreenState"); 457 screenState.setSrcname("ScreenState"); 458 contentPanel.addDataFragment(new ClockDataFragment(contentPanel, screenState)); 459 Clock folder = new Clock(); 460 folder.setName("Clocks"); 461 folder.setSrcname("Clocks"); 462 ClockFolderFragment folderFragment = new ClockFolderFragment(contentPanel, folder); 463 contentPanel.addDataFragment(folderFragment); 464 clocks.forEach(it -> { 465 ClockDataFragment clockDataFragment = new ClockDataFragment(contentPanel, it); 466 clockDataFragment.parentUuid = folderFragment.uuid; 467 clockDataFragment.visible = false; 468 contentPanel.addDataFragment(clockDataFragment); 469 }); 470 } 471 } 472 loadDur()473 private void loadDur() { 474 List<Duration> dur = new ArrayList<>() { 475 }; 476 Db.getInstance().query(Sql.SYS_QUERY_TOTAL_TIME, dur); 477 if (dur != null && dur.size() > 0) { 478 DURATION = dur.get(0).getTotal(); 479 } 480 } 481 loadCpuData()482 private List<List<CpuData>> loadCpuData() { 483 List<CpuMax> cpuMaxes = new ArrayList<>() { 484 }; 485 Db.getInstance().query(Sql.SYS_QUERY_CPU_MAX, cpuMaxes); 486 if (cpuMaxes.isEmpty()) { 487 return Lists.newArrayList(); 488 } 489 int cpuMax = cpuMaxes.get(0).getCpu(); 490 List<List<CpuData>> list = new ArrayList<>(); 491 for (int index = 0; index <= cpuMax; index++) { 492 List<CpuData> cpuData = new ArrayList<>() { 493 }; 494 list.add(cpuData); 495 } 496 return list; 497 } 498 loadCpuFreqData()499 private List<List<CpuFreqData>> loadCpuFreqData() { 500 List<Cpu> cpus = new ArrayList<>() { 501 }; 502 Db.getInstance().query(Sql.SYS_QUERY_CPU_FREQ, cpus); 503 return cpus.stream().map(it -> { 504 List<CpuFreqData> cpuFreqData = new ArrayList<>() { 505 }; 506 Db.getInstance().query(Sql.SYS_QUERY_CPU_FREQ_DATA, cpuFreqData, it.getCpu()); 507 return cpuFreqData; 508 }).collect(Collectors.toList()); 509 } 510 511 /** 512 * The bottom tab is displayed when the select event is clicked. 513 * 514 * @param cpus select cpu list() 515 * @param threadIds select thread id list 516 * @param trackIds select mem track id list 517 * @param ns select start time ns and end time ns 518 * @param funTids funTids 519 */ boxSelection(final List<Integer> cpus, final List<Integer> threadIds, final List<Integer> trackIds, final List<Integer> funTids, final LeftRightNS ns)520 public void boxSelection(final List<Integer> cpus, final List<Integer> threadIds, final List<Integer> trackIds, 521 final List<Integer> funTids, final LeftRightNS ns) { 522 if (cpus.isEmpty() && threadIds.isEmpty() && trackIds.isEmpty() && funTids.isEmpty()) { 523 if (Objects.nonNull(tab)) { 524 tab.hidden(); 525 } 526 return; 527 } 528 SwingUtilities.invokeLater(() -> { 529 tab.display(); 530 tab.removeAll(); 531 if (cpus != null && !cpus.isEmpty()) { 532 TabCpuByThread cpuThread = new TabCpuByThread(); 533 TabCpuByProcess cpuProcess = new TabCpuByProcess(); 534 cpuThread.loadTabData(cpus, ns.getLeftNs(), ns.getRightNs()); 535 cpuProcess.loadTabData(cpus, ns.getLeftNs(), ns.getRightNs()); 536 tab.add("CPU by thread", cpuThread); 537 tab.add("CPU by process", cpuProcess); 538 } 539 if (threadIds != null && !threadIds.isEmpty()) { 540 TabThreadStates threadStatesTab = new TabThreadStates(); 541 threadStatesTab.loadTabData(threadIds, ns.getLeftNs(), ns.getRightNs()); 542 tab.add("Thread States", threadStatesTab); 543 } 544 if (funTids != null && !funTids.isEmpty()) { 545 TabSlices slicesTab = new TabSlices(); 546 slicesTab.loadTabData(funTids, ns.getLeftNs(), ns.getRightNs()); 547 tab.add("Slices", slicesTab); 548 } 549 if (trackIds != null && !trackIds.isEmpty()) { 550 TabCounter counterTab = new TabCounter(); 551 counterTab.loadTabData(trackIds, ns.getLeftNs(), ns.getRightNs()); 552 tab.add("Counters", counterTab); 553 } 554 tab.add("Logs", tabLogTable); 555 tabLogTable.query(true); 556 }); 557 } 558 559 /** 560 * The bottom tab is displayed when the method event is clicked. 561 * 562 * @param bean function 563 */ clickFunctionData(final FunctionBean bean)564 public void clickFunctionData(final FunctionBean bean) { 565 cancelRangeSelect(); 566 ArrayList<ScrollSlicePanel.SliceData> dataSource = new ArrayList<>(); 567 dataSource.add(ScrollSlicePanel.createSliceData("Name", bean.getFunName(), false)); 568 dataSource.add(ScrollSlicePanel.createSliceData("Category", bean.getCategory(), false)); 569 dataSource.add( 570 ScrollSlicePanel.createSliceData("StartTime", TimeUtils.getTimeString(bean.getStartTime()) + "", false)); 571 dataSource 572 .add(ScrollSlicePanel.createSliceData("Duration", TimeUtils.getTimeString(bean.getDuration()) + "", false)); 573 if (bean.isBinder()) { 574 List<BinderArg> binderArgList = new ArrayList<>() { 575 }; 576 Db.getInstance().query(Sql.SYS_QUERY_BINDER_ARGS_BY_ARGSET, binderArgList, bean.getArgSetId()); 577 binderArgList.forEach(it -> { 578 dataSource.add(ScrollSlicePanel.createSliceData(it.getKeyName(), it.getStrValue(), false)); 579 }); 580 dataSource.add(ScrollSlicePanel.createSliceData("depth", bean.getDepth().toString(), false)); 581 dataSource.add(ScrollSlicePanel.createSliceData("arg_set_id", bean.getArgSetId().toString(), false)); 582 } 583 SwingUtilities.invokeLater(() -> { 584 if (Objects.nonNull(tab)) { 585 tab.display(); 586 tab.removeAll(); 587 ScrollSlicePanel ssp = new ScrollSlicePanel(); 588 ssp.setData("Slice Details", dataSource, null); 589 tab.add("Current Selection", ssp); 590 tab.add("Logs", tabLogTable); 591 tabLogTable.query(true); 592 } 593 }); 594 } 595 596 /** 597 * The bottom tab is displayed when the method event is clicked. 598 * 599 * @param bean function 600 */ clickAsyncFunctionData(final AsyncEvent bean)601 public void clickAsyncFunctionData(final AsyncEvent bean) { 602 cancelRangeSelect(); 603 ArrayList<ScrollSlicePanel.SliceData> dataSource = new ArrayList<>(); 604 dataSource.add(ScrollSlicePanel.createSliceData("Name", bean.getName(), false)); 605 dataSource.add(ScrollSlicePanel.createSliceData("Cookie", bean.getCookie().toString(), false)); 606 dataSource.add( 607 ScrollSlicePanel.createSliceData("StartTime", TimeUtils.getTimeString(bean.getStartTime()) + "", false)); 608 dataSource 609 .add(ScrollSlicePanel.createSliceData("Duration", TimeUtils.getTimeString(bean.getDuration()) + "", false)); 610 SwingUtilities.invokeLater(() -> { 611 if (Objects.nonNull(tab)) { 612 tab.display(); 613 tab.removeAll(); 614 ScrollSlicePanel ssp = new ScrollSlicePanel(); 615 ssp.setData("Slice Details", dataSource, null); 616 tab.add("Current Selection", ssp); 617 tab.add("Logs", tabLogTable); 618 tabLogTable.query(true); 619 } 620 }); 621 } 622 623 /** 624 * The bottom tab is displayed when the clock data event is clicked. 625 * 626 * @param clock clock data 627 */ clickClockData(final ClockData clock)628 public void clickClockData(final ClockData clock) { 629 cancelRangeSelect(); 630 ArrayList<ScrollSlicePanel.SliceData> dataSource = new ArrayList<>(); 631 dataSource 632 .add(ScrollSlicePanel.createSliceData("Start time", TimeUtils.getTimeString(clock.getStartTime()), false)); 633 dataSource.add(ScrollSlicePanel.createSliceData("Value", String.valueOf(clock.getValue()), false)); 634 dataSource.add(ScrollSlicePanel.createSliceData("Delta", String.valueOf(clock.getDelta()), false)); 635 dataSource.add( 636 ScrollSlicePanel.createSliceData("Duration", TimeUtils.getTimeString(clock.getDuration()) + "", false)); 637 SwingUtilities.invokeLater(() -> { 638 if (Objects.nonNull(tab)) { 639 tab.display(); 640 tab.removeAll(); 641 ScrollSlicePanel ssp = new ScrollSlicePanel(); 642 ssp.setData("Counter Details", dataSource, null); 643 tab.add("Current Selection", ssp); 644 tab.add("Logs", tabLogTable); 645 tabLogTable.query(true); 646 } 647 }); 648 } 649 650 /** 651 * The bottom tab is displayed when the mem data event is clicked. 652 * 653 * @param mem mem data 654 */ clickMemData(final ProcessMemData mem)655 public void clickMemData(final ProcessMemData mem) { 656 cancelRangeSelect(); 657 ArrayList<ScrollSlicePanel.SliceData> dataSource = new ArrayList<>(); 658 dataSource 659 .add(ScrollSlicePanel.createSliceData("Start time", TimeUtils.getTimeString(mem.getStartTime()), false)); 660 dataSource.add(ScrollSlicePanel.createSliceData("Value", String.valueOf(mem.getValue()), false)); 661 dataSource.add(ScrollSlicePanel.createSliceData("Delta", String.valueOf(mem.getDelta()), false)); 662 dataSource 663 .add(ScrollSlicePanel.createSliceData("Duration", TimeUtils.getTimeString(mem.getDuration()) + "", false)); 664 SwingUtilities.invokeLater(() -> { 665 tab.display(); 666 tab.removeAll(); 667 ScrollSlicePanel ssp = new ScrollSlicePanel(); 668 ssp.setData("Counter Details", dataSource, null); 669 tab.add("Current Selection", ssp); 670 tab.add("Logs", tabLogTable); 671 tabLogTable.query(true); 672 }); 673 } 674 675 /** 676 * When you click the CPU event, the bottom tab is displayed. 677 * 678 * @param threadData thread 679 */ clickThreadData(final ThreadData threadData)680 public void clickThreadData(final ThreadData threadData) { 681 cancelRangeSelect(); 682 ArrayList<ScrollSlicePanel.SliceData> dataSource = new ArrayList<>(); 683 dataSource.add(ScrollSlicePanel 684 .createSliceData("StartTime", TimeUtils.getTimeString(threadData.getStartTime()) + "", false)); 685 dataSource.add(ScrollSlicePanel 686 .createSliceData("Duration", TimeUtils.getTimeString(threadData.getDuration()) + "", false)); 687 String state = Utils.getEndState(threadData.getState()); 688 if ("Running".equals(Utils.getEndState(threadData.getState()))) { 689 state = state + " on CPU " + threadData.getCpu(); 690 } 691 dataSource.add(ScrollSlicePanel.createSliceData("State", state, true)); 692 String processName = threadData.getProcessName(); 693 if (processName == null || processName.isEmpty() || processName.equalsIgnoreCase("null")) { 694 processName = threadData.getThreadName(); 695 } 696 dataSource 697 .add(ScrollSlicePanel.createSliceData("Process", processName + " [" + threadData.getPid() + "]", false)); 698 SwingUtilities.invokeLater(() -> { 699 if (Objects.nonNull(tab)) { 700 tab.display(); 701 tab.removeAll(); 702 ScrollSlicePanel ssp = new ScrollSlicePanel(); 703 ssp.setData("Thread State", dataSource, null); 704 ssp.setScrollSliceLinkListener(bean -> { 705 contentPanel.scrollToCpu(threadData.getCpu(), threadData.getStartTime()); 706 }); 707 tab.add("Current Selection", ssp); 708 tab.add("Logs", tabLogTable); 709 tabLogTable.query(true); 710 } 711 }); 712 } 713 714 /** 715 * The bottom tab is displayed when you click the CPU event. 716 * 717 * @param cpu cpu 718 */ clickCpuData(final CpuData cpu)719 public void clickCpuData(final CpuData cpu) { 720 cancelRangeSelect(); 721 ArrayList<ScrollSlicePanel.SliceData> dataSource = new ArrayList<>(); 722 String process = cpu.getProcessName(); 723 int processId = cpu.getProcessId(); 724 if (cpu.getProcessName() == null || cpu.getProcessName().isEmpty()) { 725 process = cpu.getName(); 726 processId = cpu.getTid(); 727 } 728 dataSource.add(ScrollSlicePanel.createSliceData("Process", process + " [" + processId + "]", false)); 729 dataSource.add(ScrollSlicePanel.createSliceData("Thread", cpu.getName() + " [" + cpu.getTid() + "]", true)); 730 dataSource.add(ScrollSlicePanel.createSliceData("CmdLine", cpu.getProcessCmdLine() + "", false)); 731 dataSource.add( 732 ScrollSlicePanel.createSliceData("StartTime", TimeUtils.getTimeString(cpu.getStartTime()) + "", false)); 733 dataSource 734 .add(ScrollSlicePanel.createSliceData("Duration", TimeUtils.getTimeString(cpu.getDuration()) + "", false)); 735 dataSource.add(ScrollSlicePanel.createSliceData("Prio", cpu.getPriority() + "", false)); 736 dataSource.add(ScrollSlicePanel.createSliceData("End State", Utils.getEndState(cpu.getEndState()), false)); 737 // wakeup description 738 CompletableFuture.runAsync(() -> { 739 Optional<WakeupBean> wb = queryWakeUpThread(cpu); 740 SwingUtilities.invokeLater(() -> { 741 contentPanel.setWakeupBean(wb.orElse(null)); 742 tab.display(); 743 tab.removeAll(); 744 ScrollSlicePanel ssp = new ScrollSlicePanel(); 745 ssp.setData("Slice Details", dataSource, wb.orElse(null)); 746 ssp.setScrollSliceLinkListener(bean -> { 747 contentPanel 748 .scrollToThread(cpu.getProcessId(), cpu.getProcessName(), cpu.getTid(), cpu.getStartTime(), 749 tab.getHeight()); 750 }); 751 tab.add("Current Selection", ssp); 752 tab.add("Logs", tabLogTable); 753 tabLogTable.query(true); 754 repaint(); 755 }); 756 }, Utils.getPool()).whenComplete((unused, throwable) -> { 757 if (Objects.nonNull(throwable)) { 758 throwable.printStackTrace(); 759 } 760 }); 761 } 762 queryWakeUpThread(final CpuData cpuData)763 private Optional<WakeupBean> queryWakeUpThread(final CpuData cpuData) { 764 WakeupBean wb = null; 765 List<WakeupTime> result = new ArrayList<>() { 766 }; 767 Db.getInstance() 768 .query(Sql.SYS_GET_WAKEUP_TIME, result, cpuData.getId(), cpuData.getStartTime(), cpuData.getId(), 769 cpuData.getStartTime()); 770 if (result != null && result.size() > 0) { 771 WakeupTime wakeupTime = result.get(0); 772 if (wakeupTime.getWakeTs() < wakeupTime.getPreRow()) { 773 return Optional.ofNullable(wb); 774 } 775 List<WakeupBean> beans = new ArrayList<>() { 776 }; 777 Db.getInstance().query(Sql.SYS_GET_WAKEUP_THREAD, beans, wakeupTime.getWakeTs(), wakeupTime.getWakeTs(), 778 wakeupTime.getWakeTs()); 779 if (beans != null && beans.size() > 0) { 780 wb = beans.get(0); 781 wb.setWakeupTime(wakeupTime.getWakeTs() - wakeupTime.getStartTs()); 782 wb.setSchedulingLatency(cpuData.getStartTime() - wb.getWakeupTime()); 783 if (wb.getWakeupProcess() == null) { 784 wb.setWakeupProcess(wb.getWakeupThread()); 785 } 786 if (wb.getWakeupPid() == null) { 787 wb.setWakeupPid(wb.getWakeupTid()); 788 } 789 wb.setSchedulingDesc(Db.getSql("QueryWakeUpThread_Desc")); 790 } 791 } 792 return Optional.ofNullable(wb); 793 } 794 795 /** 796 * Evoking the red flag corresponds to the tabPanel at the bottom. 797 * 798 * @param flagBean flag 799 */ clickTimeFlag(final FlagBean flagBean)800 public void clickTimeFlag(final FlagBean flagBean) { 801 cancelRangeSelect(); 802 clicked = true; 803 ScrollFlagPanel flagPanel = new ScrollFlagPanel(flagBean); 804 flagPanel.setFlagListener(new IFlagListener() { 805 @Override 806 public void flagRemove(final FlagBean flag) { 807 flag.remove(); 808 viewport.rulerFragment.repaint(); 809 tab.removeAll(); 810 tab.hidden(); 811 } 812 813 @Override 814 public void flagChange(final FlagBean flag) { 815 if (flag.getName() != null && !flag.getName().isEmpty()) { 816 flagBean.setName(flag.getName()); 817 } 818 flagBean.setColor(flag.getColor()); 819 viewport.rulerFragment.repaint(); 820 } 821 }); 822 SwingUtilities.invokeLater(() -> { 823 if (Objects.nonNull(tab)) { 824 tab.display(); 825 tab.removeAll(); 826 tab.add("Current Selection", flagPanel); 827 repaint(); 828 } 829 }); 830 } 831 832 @Override keyTyped(final KeyEvent event)833 public void keyTyped(final KeyEvent event) { 834 } 835 836 @Override keyPressed(final KeyEvent event)837 public void keyPressed(final KeyEvent event) { 838 switch (event.getExtendedKeyCode()) { 839 case VK_A: 840 wheelSize = viewport.rulerFragment.getScale() * -0.2; 841 translation(); 842 break; 843 case VK_D: 844 wheelSize = viewport.rulerFragment.getScale() * 0.2; 845 translation(); 846 break; 847 case VK_W: 848 wheelSize = viewport.rulerFragment.getScale() * -0.2; 849 lefPercent = 0.5; 850 scale(); 851 break; 852 case VK_S: 853 wheelSize = viewport.rulerFragment.getScale() * 0.2; 854 lefPercent = 0.5; 855 scale(); 856 break; 857 case VK_F: 858 keyPressedVKF(event); 859 break; 860 case VK_SHIFT: 861 case VK_CONTROL: 862 if (!isUserInteraction) { 863 isUserInteraction = true; 864 contentPanel.addMouseWheelListener(this); 865 } 866 break; 867 default: 868 break; 869 } 870 } 871 keyPressedVKF(KeyEvent event)872 private void keyPressedVKF(KeyEvent event) { 873 if (event.isControlDown() || event.isMetaDown()) { 874 for (AbstractDataFragment frg : viewport.favoriteFragments) { 875 viewport.cancel(frg); 876 } 877 String keyword = Optional.ofNullable(JOptionPane 878 .showInputDialog(null, "Search for pid uid name", "Search", JOptionPane.PLAIN_MESSAGE, null, null, "")) 879 .map(it -> it.toString().trim()).orElse(""); 880 if (keyword == null || keyword.isEmpty()) { 881 keyPressedVKFEmptyKeyword(); 882 } else { 883 contentPanel.fragmentList.stream().forEach(it -> { 884 if (it instanceof ThreadDataFragment) { 885 ThreadDataFragment fr1 = (ThreadDataFragment) it; 886 if (String.valueOf(fr1.thread.getTid()).equals(keyword)) { 887 it.setVisible(true); 888 } else if (fr1.thread.getThreadName() != null 889 && fr1.thread.getThreadName().indexOf(keyword) != -1) { 890 it.setVisible(true); 891 } else { 892 it.setVisible(false); 893 } 894 } 895 if (it instanceof ProcessDataFragment) { 896 ProcessDataFragment it1 = (ProcessDataFragment) it; 897 if (it1.getProcess().getName() != null && it1.getProcess().getName().indexOf(keyword) != -1) { 898 it1.getExpandGraph().setExpand(true); 899 it.setVisible(true); 900 } else if (it1.getProcess().getPid().toString().equals(keyword)) { 901 it1.getExpandGraph().setExpand(true); 902 it.setVisible(true); 903 } else { 904 it.setVisible(false); 905 } 906 } 907 }); 908 } 909 contentPanel.refresh(); 910 } 911 } 912 keyPressedVKFEmptyKeyword()913 private void keyPressedVKFEmptyKeyword() { 914 contentPanel.fragmentList.stream().forEach(it -> { 915 if (it instanceof ThreadDataFragment || it instanceof MemDataFragment 916 || it instanceof AsyncEventDataFragment || it instanceof FunctionDataFragment) { 917 it.setVisible(false); 918 } else { 919 if (it instanceof ProcessDataFragment) { 920 ProcessDataFragment it1 = (ProcessDataFragment) it; 921 it1.getExpandGraph().setExpand(false); 922 } 923 it.setVisible(true); 924 } 925 }); 926 } 927 928 @Override keyReleased(final KeyEvent event)929 public void keyReleased(final KeyEvent event) { 930 switch (event.getExtendedKeyCode()) { 931 case VK_SHIFT: 932 case VK_CONTROL: 933 if (isUserInteraction) { 934 isUserInteraction = false; 935 contentPanel.removeMouseWheelListener(this); 936 contentPanel.fragmentList.forEach(it -> it.keyReleased(event)); 937 contentPanel.fragmentList.forEach(it -> it.drawFrame()); 938 } 939 break; 940 default: 941 break; 942 } 943 } 944 945 @Override mouseClicked(final MouseEvent event)946 public void mouseClicked(final MouseEvent event) { 947 clicked = false; 948 viewport.mouseClicked(event); 949 // Select the area, judge to click on the tab in the area to restore the display 950 Rectangle rectangle = new Rectangle(contentPanel.x1, contentPanel.y1, contentPanel.x2 - contentPanel.x1, 951 contentPanel.y2 - contentPanel.y1); 952 if (rectangle.contains(event.getPoint())) { 953 tab.display(); 954 } else { 955 if (SwingUtilities.convertMouseEvent(contentPanel, event, AnalystPanel.this).getY() > TimeViewPort.height) { 956 contentPanel.fragmentList.stream().filter(it -> it.getRect().contains(event.getPoint())) 957 .forEach(fragment -> fragment.mouseClicked(event)); 958 } 959 if (!clicked) { 960 tab.hidden(); 961 contentPanel.fragmentList.stream().findFirst().ifPresent(it -> { 962 it.clearSelected(); 963 }); 964 contentPanel.clearWakeupAndBoxSelect(); 965 } 966 } 967 } 968 969 @Override mousePressed(final MouseEvent event)970 public void mousePressed(final MouseEvent event) { 971 viewport.mousePressed(event); 972 if (SwingUtilities.convertMouseEvent(contentPanel, event, AnalystPanel.this).getY() > TimeViewPort.height) { 973 Rectangle rect = new Rectangle(0, 0, viewport.getWidth(), TimeViewPort.height); 974 if (!rect.contains(event.getPoint()) && Utils.getX(event.getPoint()) > 200) { 975 if (getCursor().getType() == Cursor.DEFAULT_CURSOR) { 976 contentPanel.startPoint = event.getPoint(); 977 } 978 contentPanel.drawRangeSelect = true; 979 contentPanel.fragmentList.forEach(fragment -> fragment.mousePressed(event)); 980 } 981 } 982 } 983 984 @Override mouseReleased(final MouseEvent event)985 public void mouseReleased(final MouseEvent event) { 986 if (SwingUtilities.convertMouseEvent(contentPanel, event, AnalystPanel.this).getY() > TimeViewPort.height) { 987 contentPanel.drawRangeSelect = false; 988 contentPanel.fragmentList.stream().filter(it -> !(it instanceof CpuDataFragment)) 989 .forEach(fragment -> fragment.mouseReleased(event)); 990 } else { 991 contentPanel.fragmentList.forEach(it -> it.mouseReleased(event)); 992 if (isUserInteraction) { 993 isUserInteraction = false; 994 contentPanel.fragmentList.forEach(it -> it.drawFrame()); 995 } 996 } 997 if (Objects.nonNull(contentPanel.startPoint) && Objects.nonNull(contentPanel.endPoint)) { 998 if (contentPanel.startPoint.getX() > contentPanel.endPoint.getX()) { 999 Point tmp = contentPanel.startPoint; 1000 contentPanel.startPoint = contentPanel.endPoint; 1001 contentPanel.endPoint = tmp; 1002 } 1003 } 1004 contentPanel.repaint(); 1005 } 1006 1007 @Override mouseEntered(final MouseEvent event)1008 public void mouseEntered(final MouseEvent event) { 1009 if (SwingUtilities.convertMouseEvent(contentPanel, event, AnalystPanel.this).getY() > TimeViewPort.height) { 1010 contentPanel.fragmentList.forEach(fragment -> fragment.mouseEntered(event)); 1011 } 1012 } 1013 1014 @Override mouseExited(final MouseEvent event)1015 public void mouseExited(final MouseEvent event) { 1016 if (SwingUtilities.convertMouseEvent(contentPanel, event, AnalystPanel.this).getY() > TimeViewPort.height) { 1017 contentPanel.fragmentList.forEach(fragment -> fragment.mouseExited(event)); 1018 } 1019 } 1020 1021 @Override mouseDragged(final MouseEvent event)1022 public void mouseDragged(final MouseEvent event) { 1023 viewport.mouseDragged(event); 1024 isUserInteraction = true; 1025 /** 1026 * If the drag range is in the area below the time axis, 1027 * the range selection function appears,and the tab box pops up 1028 */ 1029 if (SwingUtilities.convertMouseEvent(contentPanel, event, AnalystPanel.this).getY() > TimeViewPort.height) { 1030 Rectangle rect = new Rectangle(0, 0, viewport.getWidth(), TimeViewPort.height); 1031 if (!rect.contains(event.getPoint()) && Utils.getX(event.getPoint()) > 200) { 1032 long startNSTmp = Math.min(viewport.rulerFragment.getLeftNS(), viewport.rulerFragment.getRightNS()); 1033 long endNSTmp = Math.max(viewport.rulerFragment.getLeftNS(), viewport.rulerFragment.getRightNS()); 1034 long dur = endNSTmp - startNSTmp; 1035 if (getCursor().getType() == Cursor.W_RESIZE_CURSOR) { 1036 contentPanel.startPoint = event.getPoint(); 1037 contentPanel.x1 = Math.min(Utils.getX(contentPanel.startPoint), Utils.getX(contentPanel.endPoint)); 1038 contentPanel.x2 = Math.max(Utils.getX(contentPanel.startPoint), Utils.getX(contentPanel.endPoint)); 1039 contentPanel.rangeStartNS = 1040 (contentPanel.x1 - 200) * dur / (viewport.rulerFragment.getRect().width) + startNSTmp; 1041 contentPanel.rangeEndNS = 1042 (contentPanel.x2 - 200) * dur / (viewport.rulerFragment.getRect().width) + startNSTmp; 1043 } else if (getCursor().getType() == Cursor.E_RESIZE_CURSOR) { 1044 contentPanel.endPoint = event.getPoint(); 1045 contentPanel.x1 = Math.min(Utils.getX(contentPanel.startPoint), Utils.getX(contentPanel.endPoint)); 1046 contentPanel.x2 = Math.max(Utils.getX(contentPanel.startPoint), Utils.getX(contentPanel.endPoint)); 1047 contentPanel.rangeStartNS = 1048 (contentPanel.x1 - 200) * dur / (viewport.rulerFragment.getRect().width) + startNSTmp; 1049 contentPanel.rangeEndNS = 1050 (contentPanel.x2 - 200) * dur / (viewport.rulerFragment.getRect().width) + startNSTmp; 1051 } else { 1052 contentPanel.endPoint = event.getPoint(); 1053 if (Objects.nonNull(contentPanel.startPoint)) { 1054 contentPanel.x1 = 1055 Math.min(Utils.getX(contentPanel.startPoint), Utils.getX(contentPanel.endPoint)); 1056 contentPanel.y1 = 1057 Math.min(Utils.getY(contentPanel.startPoint), Utils.getY(contentPanel.endPoint)); 1058 contentPanel.x2 = 1059 Math.max(Utils.getX(contentPanel.startPoint), Utils.getX(contentPanel.endPoint)); 1060 contentPanel.y2 = 1061 Math.max(Utils.getY(contentPanel.startPoint), Utils.getY(contentPanel.endPoint)); 1062 contentPanel.rangeStartNS = 1063 (contentPanel.x1 - 200) * dur / (viewport.rulerFragment.getRect().width) + startNSTmp; 1064 contentPanel.rangeEndNS = 1065 (contentPanel.x2 - 200) * dur / (viewport.rulerFragment.getRect().width) + startNSTmp; 1066 } 1067 } 1068 contentPanel.drawRangeSelectData = true; 1069 contentPanel.repaint(); 1070 } 1071 } 1072 } 1073 1074 @Override mouseMoved(final MouseEvent event)1075 public void mouseMoved(final MouseEvent event) { 1076 viewport.mouseMoved(event); 1077 if (SwingUtilities.convertMouseEvent(contentPanel, event, AnalystPanel.this).getY() > TimeViewPort.height) { 1078 if (event.getY() < Utils.getY(tab.getBounds())) { 1079 contentPanel.requestFocusInWindow(); 1080 } 1081 contentPanel.fragmentList.forEach(fragment -> fragment.mouseMoved(event)); 1082 } 1083 Rectangle rect1 = new Rectangle(contentPanel.x1 - 2, contentPanel.y1, 4, contentPanel.y2 - contentPanel.y1); 1084 Rectangle rect2 = new Rectangle(contentPanel.x2 - 2, contentPanel.y1, 4, contentPanel.y2 - contentPanel.y1); 1085 if (rect1.contains(event.getPoint())) { 1086 setCursor(wCursor); 1087 } else if (rect2.contains(event.getPoint())) { 1088 setCursor(eCursor); 1089 } else { 1090 setCursor(defaultCursor); 1091 } 1092 } 1093 1094 @Override mouseWheelMoved(final MouseWheelEvent event)1095 public void mouseWheelMoved(final MouseWheelEvent event) { 1096 if (event.isShiftDown() && !event.isControlDown()) { // Pan 1097 long scale = viewport.rulerFragment.getScale(); 1098 if (Math.abs(event.getPreciseWheelRotation()) >= 1) { 1099 wheelSize = scale * event.getPreciseWheelRotation() * defaultScale; 1100 } else { 1101 wheelSize = scale * event.getPreciseWheelRotation(); 1102 } 1103 translation(); 1104 } 1105 if (event.isControlDown() && !event.isShiftDown()) { // Zoom 1106 if (Math.abs(event.getPreciseWheelRotation()) >= 1) { 1107 wheelSize = viewport.rulerFragment.getScale() * event.getPreciseWheelRotation() * defaultScale; 1108 } else { 1109 wheelSize = viewport.rulerFragment.getScale() * event.getPreciseWheelRotation(); 1110 } 1111 int rulerFragmentWidth = viewport.rulerFragment.getRect().width; 1112 lefPercent = (event.getX() - Utils.getX(viewport.rulerFragment.getRect())) * 1.0 / rulerFragmentWidth; 1113 if (scaleMin(event)) { 1114 scale(); 1115 } 1116 } 1117 } 1118 scaleMin(MouseWheelEvent event)1119 private boolean scaleMin(MouseWheelEvent event) { 1120 if (event.getPreciseWheelRotation() < 0) { // Zoom out 1121 long rightNS = viewport.rulerFragment.getRightNS(); 1122 long leftNS = viewport.rulerFragment.getLeftNS(); 1123 long centerNS; 1124 final int minrul = 1000; 1125 if (rightNS - leftNS <= minrul) { 1126 rightNS = leftNS + minrul; 1127 centerNS = leftNS; 1128 viewport.rulerFragment.setRange(leftNS, rightNS, centerNS); 1129 viewport.cpuFragment.setRange(leftNS, rightNS); 1130 for (AbstractDataFragment fragment : viewport.favoriteFragments) { 1131 fragment.range(leftNS, rightNS); 1132 } 1133 repaint(); 1134 return false; 1135 } 1136 } 1137 return true; 1138 } 1139 scale()1140 private void scale() { 1141 if (lefPercent < 0) { 1142 lefPercent = 0; 1143 } 1144 if (lefPercent > 1) { 1145 lefPercent = 1; 1146 } 1147 rightPercent = 1 - lefPercent; 1148 if (lefPercent > 0) { 1149 double leftNs = viewport.rulerFragment.getLeftNS() - this.wheelSize * lefPercent; 1150 viewport.rulerFragment.setLeftNS((long) leftNs); 1151 } 1152 if (rightPercent > 0) { 1153 double rightNs = viewport.rulerFragment.getRightNS() + this.wheelSize * rightPercent; 1154 viewport.rulerFragment.setRightNS((long) rightNs); 1155 } 1156 if (viewport.rulerFragment.getLeftNS() <= 0) { 1157 viewport.rulerFragment.setLeftNS(0); 1158 } 1159 if (viewport.rulerFragment.getRightNS() >= DURATION) { 1160 viewport.rulerFragment.setRightNS(DURATION); 1161 } 1162 viewport.rulerFragment.setCenterNS(viewport.rulerFragment.getLeftNS()); 1163 viewport.rulerFragment.setRange(viewport.rulerFragment.getLeftNS(), viewport.rulerFragment.getRightNS(), 1164 viewport.rulerFragment.getCenterNS()); 1165 viewport.cpuFragment.setRange(viewport.rulerFragment.getLeftNS(), viewport.rulerFragment.getRightNS()); 1166 if (lefPercent > 0) { 1167 startNS = viewport.leftFragment.getStartNS(); 1168 startNS -= wheelSize * lefPercent; 1169 if (startNS > 0) { 1170 viewport.leftFragment.setStartTime(startNS); 1171 } else { 1172 viewport.leftFragment.setStartTime(0); 1173 } 1174 } 1175 for (AbstractDataFragment fragment : viewport.favoriteFragments) { 1176 fragment.range(viewport.rulerFragment.getLeftNS(), viewport.rulerFragment.getRightNS()); 1177 } 1178 resetRangePoint(); 1179 contentPanel.repaint(); 1180 } 1181 translation()1182 private void translation() { 1183 long leftNS = viewport.rulerFragment.getLeftNS(); 1184 long rightNS = viewport.rulerFragment.getRightNS(); 1185 long centerNS; 1186 1187 if (leftNS + wheelSize <= 0) { 1188 rangeNs = rightNS - leftNS; 1189 leftNS = 0; 1190 rightNS = (long) rangeNs; 1191 centerNS = leftNS; 1192 viewport.rulerFragment.setRange(leftNS, rightNS, centerNS); 1193 viewport.cpuFragment.setRange(leftNS, rightNS); 1194 viewport.leftFragment.setStartTime(0); 1195 } else if (rightNS + wheelSize >= DURATION) { 1196 rangeNs = rightNS - leftNS; 1197 rightNS = DURATION; 1198 leftNS = (long) (DURATION - rangeNs); 1199 centerNS = leftNS; 1200 viewport.rulerFragment.setRange(leftNS, rightNS, centerNS); 1201 viewport.cpuFragment.setRange(leftNS, rightNS); 1202 viewport.leftFragment.setStartTime(leftNS); 1203 } else { 1204 leftNS += wheelSize; 1205 rightNS += wheelSize; 1206 centerNS = leftNS; 1207 viewport.rulerFragment.setRange(leftNS, rightNS, centerNS); 1208 viewport.cpuFragment.setRange(leftNS, rightNS); 1209 startNS = viewport.leftFragment.getStartNS(); 1210 startNS += wheelSize; 1211 viewport.leftFragment.setStartTime(startNS); 1212 } 1213 1214 // Slide the icons that need to be viewed in the timeShaft collection 1215 for (AbstractDataFragment fragment : viewport.favoriteFragments) { 1216 fragment.range(leftNS, rightNS); 1217 } 1218 resetRangePoint(); 1219 contentPanel.repaint(); 1220 } 1221 resetRangePoint()1222 private void resetRangePoint() { 1223 contentPanel.fragmentList.stream().findFirst().ifPresent(it -> { 1224 if (Objects.nonNull(contentPanel.startPoint)) { 1225 Utils.setX(contentPanel.startPoint, it.getX(contentPanel.rangeStartNS) + 200); 1226 contentPanel.x1 = Utils.getX(contentPanel.startPoint); 1227 } 1228 if (Objects.nonNull(contentPanel.endPoint)) { 1229 Utils.setX(contentPanel.endPoint, it.getX(contentPanel.rangeEndNS) + 200); 1230 contentPanel.x2 = Utils.getX(contentPanel.endPoint); 1231 } 1232 }); 1233 } 1234 cancelRangeSelect()1235 private void cancelRangeSelect() { 1236 contentPanel.startPoint = null; 1237 contentPanel.endPoint = null; 1238 } 1239 getCpuNum()1240 public static int getCpuNum() { 1241 return cpuNum; 1242 } 1243 setCpuNum(int cpuNum)1244 public static void setCpuNum(int cpuNum) { 1245 AnalystPanel.cpuNum = cpuNum; 1246 } 1247 getiAsyncFunctionDataClick()1248 public static IAsyncFunctionDataClick getiAsyncFunctionDataClick() { 1249 return iAsyncFunctionDataClick; 1250 } 1251 setiAsyncFunctionDataClick(IAsyncFunctionDataClick iAsyncFunctionDataClick)1252 public static void setiAsyncFunctionDataClick(IAsyncFunctionDataClick iAsyncFunctionDataClick) { 1253 AnalystPanel.iAsyncFunctionDataClick = iAsyncFunctionDataClick; 1254 } 1255 getiClockDataClick()1256 public static IClockDataClick getiClockDataClick() { 1257 return iClockDataClick; 1258 } 1259 setiClockDataClick(IClockDataClick iClockDataClick)1260 public static void setiClockDataClick(IClockDataClick iClockDataClick) { 1261 AnalystPanel.iClockDataClick = iClockDataClick; 1262 } 1263 getiMemDataClick()1264 public static IMemDataClick getiMemDataClick() { 1265 return iMemDataClick; 1266 } 1267 setiMemDataClick(IMemDataClick iMemDataClick)1268 public static void setiMemDataClick(IMemDataClick iMemDataClick) { 1269 AnalystPanel.iMemDataClick = iMemDataClick; 1270 } 1271 getiFlagClick()1272 public static IFlagClick getiFlagClick() { 1273 return iFlagClick; 1274 } 1275 setiFlagClick(IFlagClick iFlagClick)1276 public static void setiFlagClick(IFlagClick iFlagClick) { 1277 AnalystPanel.iFlagClick = iFlagClick; 1278 } 1279 getDURATION()1280 public static long getDURATION() { 1281 return DURATION; 1282 } 1283 setDURATION(long DURATION)1284 public static void setDURATION(long DURATION) { 1285 AnalystPanel.DURATION = DURATION; 1286 } 1287 1288 /** 1289 * cpu data click callback 1290 */ 1291 public interface ICpuDataClick { 1292 /** 1293 * cpu data click callback 1294 * 1295 * @param cpu cpu 1296 */ click(CpuData cpu)1297 void click(CpuData cpu); 1298 } 1299 1300 /** 1301 * thread data click callback 1302 */ 1303 public interface IThreadDataClick { 1304 /** 1305 * thread data click callback 1306 * 1307 * @param data thread 1308 */ click(ThreadData data)1309 void click(ThreadData data); 1310 } 1311 1312 /** 1313 * function data click callback 1314 */ 1315 public interface IFunctionDataClick { 1316 /** 1317 * function data click callback 1318 * 1319 * @param data function 1320 */ click(FunctionBean data)1321 void click(FunctionBean data); 1322 } 1323 1324 /** 1325 * async function data click callback 1326 */ 1327 public interface IAsyncFunctionDataClick { 1328 /** 1329 * function data click callback 1330 * 1331 * @param data function 1332 */ click(AsyncEvent data)1333 void click(AsyncEvent data); 1334 } 1335 1336 /** 1337 * function data click callback 1338 */ 1339 public interface IClockDataClick { 1340 /** 1341 * function data click callback 1342 * 1343 * @param data function 1344 */ click(ClockData data)1345 void click(ClockData data); 1346 } 1347 1348 /** 1349 * mem data click callback 1350 */ 1351 public interface IMemDataClick { 1352 /** 1353 * mem data click callback 1354 * 1355 * @param data function 1356 */ click(ProcessMemData data)1357 void click(ProcessMemData data); 1358 } 1359 1360 /** 1361 * flag click callback 1362 */ 1363 public interface IFlagClick { 1364 /** 1365 * flag click callback 1366 * 1367 * @param data flag 1368 */ click(FlagBean data)1369 void click(FlagBean data); 1370 } 1371 1372 /** 1373 * wrap left ns and right ns 1374 */ 1375 public static class LeftRightNS { 1376 private long leftNs; 1377 private long rightNs; 1378 1379 /** 1380 * Gets the value of leftNs . 1381 * 1382 * @return the value of long 1383 */ getLeftNs()1384 public long getLeftNs() { 1385 return leftNs; 1386 } 1387 1388 /** 1389 * Sets the leftNs .You can use getLeftNs() to get the value of leftNs 1390 * 1391 * @param leftNs leftNs 1392 */ setLeftNs(long leftNs)1393 public void setLeftNs(long leftNs) { 1394 this.leftNs = leftNs; 1395 } 1396 1397 /** 1398 * Gets the value of rightNs . 1399 * 1400 * @return the value of long 1401 */ getRightNs()1402 public long getRightNs() { 1403 return rightNs; 1404 } 1405 1406 /** 1407 * Sets the rightNs .You can use getRightNs() to get the value of rightNs 1408 * 1409 * @param rightNs rightNs 1410 */ setRightNs(long rightNs)1411 public void setRightNs(long rightNs) { 1412 this.rightNs = rightNs; 1413 } 1414 } 1415 } 1416