• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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