debugger overhead proto

This commit is contained in:
Egor.Ushakov
2017-08-21 17:10:54 +03:00
parent ecd27b5418
commit 9363f8961b
6 changed files with 317 additions and 50 deletions
@@ -35,6 +35,7 @@ import com.intellij.debugger.ui.impl.ThreadsPanel;
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
import com.intellij.debugger.ui.impl.watch.MessageDescriptor;
import com.intellij.debugger.ui.impl.watch.NodeManagerImpl;
import com.intellij.debugger.ui.overhead.OverheadView;
import com.intellij.debugger.ui.tree.NodeDescriptor;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.ui.ExecutionConsole;
@@ -318,6 +319,7 @@ public class JavaDebugProcess extends XDebugProcess {
public void registerAdditionalContent(@NotNull RunnerLayoutUi ui) {
registerThreadsPanel(ui);
registerMemoryViewPanel(ui);
registerOverheadMonitor(ui);
}
@NotNull
@@ -360,7 +362,8 @@ public class JavaDebugProcess extends XDebugProcess {
}
private void registerMemoryViewPanel(@NotNull RunnerLayoutUi ui) {
if (!Registry.get("debugger.enable.memory.view").asBoolean()) return;
if (!Registry.is("debugger.enable.memory.view")) return;
final XDebugSession session = getSession();
final DebugProcessImpl process = myJavaSession.getProcess();
final InstancesTracker tracker = InstancesTracker.getInstance(myJavaSession.getProject());
@@ -395,6 +398,35 @@ public class JavaDebugProcess extends XDebugProcess {
}
}, memoryViewContent);
}
private void registerOverheadMonitor(@NotNull RunnerLayoutUi ui) {
if (!Registry.is("debugger.enable.overhead.monitor")) return;
OverheadView monitor = new OverheadView(myJavaSession.getProcess());
Content overheadContent = ui.createContent("OverheadMonitor", monitor, "Overhead", AllIcons.Debugger.Db_obsolete, null);
overheadContent.setCloseable(false);
overheadContent.setShouldDisposeContent(true);
//session.addSessionListener(new XDebugSessionListener() {
// @Override
// public void sessionStopped() {
// session.removeSessionListener(this);
// data.getTrackedStacks().clear();
// }
//});
ui.addContent(overheadContent, 0, PlaceInGrid.right, true);
//final DebuggerManagerThreadImpl managerThread = process.getManagerThread();
//ui.addListener(new ContentManagerAdapter() {
// @Override
// public void selectionChanged(ContentManagerEvent event) {
// if (event != null && event.getContent() == overheadContent) {
// classesFilteredView.setActive(overheadContent.isSelected(), managerThread);
// }
// }
//}, overheadContent);
}
};
}
@@ -1,48 +0,0 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.debugger.ui;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.openapi.util.Key;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author egor
*/
public class OverheadTimings {
public static final Key<OverheadTimings> KEY = Key.create("OVERHEAD_TIMINGS");
private final Map<Object, Long> myMap = new ConcurrentHashMap<>();
public static float get(DebugProcessImpl process, Object producer) {
return getTimings(process).myMap.get(producer);
}
public static void add(DebugProcessImpl process, Object producer, long overhead) {
getTimings(process).myMap.merge(producer, overhead, (old, value) -> old + value);
}
private static OverheadTimings getTimings(DebugProcessImpl process) {
OverheadTimings data = process.getUserData(KEY);
if (data == null) {
data = new OverheadTimings();
process.putUserData(KEY, data);
}
return data;
}
}
@@ -33,7 +33,7 @@ import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
import com.intellij.debugger.requests.ClassPrepareRequestor;
import com.intellij.debugger.requests.Requestor;
import com.intellij.debugger.settings.DebuggerSettings;
import com.intellij.debugger.ui.OverheadTimings;
import com.intellij.debugger.ui.overhead.OverheadTimings;
import com.intellij.debugger.ui.impl.watch.CompilingEvaluatorImpl;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
@@ -0,0 +1,84 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.debugger.ui.overhead;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.openapi.util.Key;
import com.intellij.util.EventDispatcher;
import org.jetbrains.annotations.NotNull;
import java.util.EventListener;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author egor
*/
public class OverheadTimings {
public static final Key<OverheadTimings> KEY = Key.create("OVERHEAD_TIMINGS");
private final EventDispatcher<OverheadTimingsListener> myEventDispatcher = EventDispatcher.create(OverheadTimingsListener.class);
private final Map<Object, Timings> myMap = new ConcurrentHashMap<>();
public static long getTime(DebugProcessImpl process, Object producer) {
Timings timings = getTimings(process).myMap.get(producer);
return timings != null ? timings.myTime : 0;
}
public static long getHits(DebugProcessImpl process, Object producer) {
Timings timings = getTimings(process).myMap.get(producer);
return timings != null ? timings.myHits : 0;
}
public static Set<Object> getProducers(DebugProcessImpl process) {
return getTimings(process).myMap.keySet();
}
public static void add(DebugProcessImpl process, Object producer, long overhead) {
OverheadTimings timings = getTimings(process);
timings.myMap.merge(producer, new Timings(1, overhead), (old, value) -> new Timings(old.myHits + 1, old.myTime + overhead));
timings.myEventDispatcher.getMulticaster().timingAdded(producer);
}
@NotNull
private static OverheadTimings getTimings(DebugProcessImpl process) {
OverheadTimings data = process.getUserData(KEY);
if (data == null) {
data = new OverheadTimings();
process.putUserData(KEY, data);
}
return data;
}
private static class Timings {
final long myHits;
final long myTime;
public Timings(long hits, long time) {
myHits = hits;
myTime = time;
}
}
static void addListener(OverheadTimingsListener listener, DebugProcessImpl process) {
getTimings(process).myEventDispatcher.addListener(listener);
}
public interface OverheadTimingsListener extends EventListener {
void timingAdded(Object producer);
}
}
@@ -0,0 +1,198 @@
/*
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.debugger.ui.overhead;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.ui.breakpoints.Breakpoint;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CustomShortcutSet;
import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.TableUtil;
import com.intellij.ui.table.JBTable;
import com.intellij.util.ui.ColumnInfo;
import com.intellij.util.ui.ListTableModel;
import com.intellij.util.ui.components.BorderLayoutPanel;
import one.util.streamex.IntStreamEx;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.event.KeyEvent;
import java.util.Comparator;
import java.util.function.Function;
/**
* @author egor
*/
public class OverheadView extends BorderLayoutPanel {
@NotNull private final DebugProcessImpl myProcess;
static final EnabledColumnInfo ENABLED_COLUMN = new EnabledColumnInfo();
static final NameColumnInfo NAME_COLUMN = new NameColumnInfo();
final JBTable myTable;
final ListTableModel<BreakpointOverheadItem> myModel;
public OverheadView(@NotNull DebugProcessImpl process) {
myProcess = process;
myModel = new ListTableModel<>(new ColumnInfo[]{
ENABLED_COLUMN,
NAME_COLUMN,
new TimingColumnInfo("hits", s -> OverheadTimings.getHits(myProcess, s.myBreakpoint)),
new TimingColumnInfo("time", s -> OverheadTimings.getTime(myProcess, s.myBreakpoint))},
StreamEx.of(OverheadTimings.getProducers(process)).select(Breakpoint.class).map(BreakpointOverheadItem::new).toList(),
3, SortOrder.DESCENDING);
myModel.setSortable(true);
myTable = new JBTable(myModel);
addToCenter(ScrollPaneFactory.createScrollPane(myTable));
TableUtil.setupCheckboxColumn(myTable.getColumnModel().getColumn(0));
OverheadTimings.addListener(o -> {
int idx = 0;
for (BreakpointOverheadItem item : myModel.getItems()) {
if (item.myBreakpoint == o) {
myModel.fireTableRowsUpdated(idx, idx);
return;
}
idx++;
}
myModel
.setItems(StreamEx.of(OverheadTimings.getProducers(process)).select(Breakpoint.class).map(BreakpointOverheadItem::new).toList());
myModel.fireTableDataChanged();
}, process);
new DumbAwareAction("Toggle") {
@Override
public void update(@NotNull AnActionEvent e) {
e.getPresentation().setEnabled(myTable.getSelectedRowCount() == 1);
}
@Override
public void actionPerformed(@NotNull final AnActionEvent e) {
getSelected().forEach(c -> c.setEnabled(!c.isEnabled()));
myTable.repaint();
}
}.registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0)), myTable);
}
private StreamEx<OverheadItem> getSelected() {
return IntStreamEx.of(myTable.getSelectedRows()).map(myTable::convertRowIndexToModel).mapToObj(myModel::getItem);
}
private static class EnabledColumnInfo extends ColumnInfo<OverheadItem, Boolean> {
public EnabledColumnInfo() {
super("");
}
@Override
public Class<?> getColumnClass() {
return Boolean.class;
}
@Nullable
@Override
public Boolean valueOf(OverheadItem item) {
return item.isEnabled();
}
@Override
public boolean isCellEditable(OverheadItem item) {
return true;
}
@Override
public void setValue(OverheadItem item, Boolean value) {
item.setEnabled(value);
}
}
private static class NameColumnInfo extends ColumnInfo<BreakpointOverheadItem, String> {
public NameColumnInfo() {
super("name");
}
@Nullable
@Override
public String valueOf(BreakpointOverheadItem aspects) {
return aspects.getName();
}
@Nullable
@Override
public Comparator<BreakpointOverheadItem> getComparator() {
return Comparator.comparing(i -> valueOf(i));
}
}
private static class TimingColumnInfo extends ColumnInfo<BreakpointOverheadItem, Long> {
private final Function<BreakpointOverheadItem, Long> myGetter;
public TimingColumnInfo(@NotNull String name, Function<BreakpointOverheadItem, Long> getter) {
super(name);
myGetter = getter;
}
@Override
public Class<?> getColumnClass() {
return Long.class;
}
@Nullable
@Override
public Long valueOf(BreakpointOverheadItem aspects) {
return myGetter.apply(aspects);
}
@Nullable
@Override
public Comparator<BreakpointOverheadItem> getComparator() {
return Comparator.comparingLong(i -> valueOf(i));
}
}
interface OverheadItem {
boolean isEnabled();
void setEnabled(boolean enabled);
String getName();
}
static class BreakpointOverheadItem implements OverheadItem {
private final Breakpoint myBreakpoint;
public BreakpointOverheadItem(Breakpoint breakpoint) {
myBreakpoint = breakpoint;
}
@Override
public String getName() {
return myBreakpoint.getDisplayName();
}
@Override
public boolean isEnabled() {
return myBreakpoint.isEnabled();
}
@Override
public void setEnabled(boolean enabled) {
myBreakpoint.setEnabled(enabled);
}
}
}
@@ -289,6 +289,7 @@ debugger.capture.points.annotations=false
debugger.resume.yourkit.threads=false
debugger.keep.step.requests=false
debugger.enable.memory.view=true
debugger.enable.overhead.monitor=false
debugger.tree.states.depth=100
analyze.exceptions.on.the.fly=false