From 3baa73c50a63c8c4b00abb0b7b66e831e30500e3 Mon Sep 17 00:00:00 2001 From: Eugene Tarassov Date: Fri, 21 Jun 2013 11:34:25 -0700 Subject: TCF Debugger: added profiler configuration dialog box --- docs/TCF Getting Started.html | 8 +- .../eclipse/tcf/internal/debug/ui/ImageCache.java | 1 + .../debug/ui/profiler/ProfilerSettingsDlg.java | 185 ++++++++++++++++ .../internal/debug/ui/profiler/ProfilerView.java | 238 ++++++++++++++------- 4 files changed, 355 insertions(+), 77 deletions(-) create mode 100644 plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/profiler/ProfilerSettingsDlg.java diff --git a/docs/TCF Getting Started.html b/docs/TCF Getting Started.html index 8bbc66f25..e5772aa35 100644 --- a/docs/TCF Getting Started.html +++ b/docs/TCF Getting Started.html @@ -43,12 +43,12 @@ below are steps to create and populate Eclipse workspace with TCF projects:

  • RSE (Remote System Explorer) SDK 3.3 or later, last tested with 3.3.1, recommended 3.3.1
    http://download.eclipse.org/tm/downloads/ -
  • Optional dependencies for Target Explorer: +
  • Optional dependencies for Target Explorer: + Eclipse update site at http://rxtx.qbang.org/eclipse/
    + Download location at http://rxtx.qbang.org/eclipse/downloads/ +
  • Clone TCF Java code from Eclipse GIT repository, using one of the following commands:
     git clone git://git.eclipse.org/gitroot/tcf/org.eclipse.tcf.git
    diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/ImageCache.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/ImageCache.java
    index 998a0439b..ed7924e86 100644
    --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/ImageCache.java
    +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/ImageCache.java
    @@ -58,6 +58,7 @@ public class ImageCache {
     
             IMG_SIGNALS = "icons/signals.gif",
             IMG_MEMORY_MAP = "icons/memory-map.gif",
    +        IMG_PROFILER = "icons/profiler.png",
     
             IMG_ARRAY_PARTITION = "icons/full/obj16/arraypartition_obj.gif",
     
    diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/profiler/ProfilerSettingsDlg.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/profiler/ProfilerSettingsDlg.java
    new file mode 100644
    index 000000000..1d5c09d08
    --- /dev/null
    +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/profiler/ProfilerSettingsDlg.java
    @@ -0,0 +1,185 @@
    +/*******************************************************************************
    + * Copyright (c) 2013 Xilinx, Inc. and others.
    + * All rights reserved. This program and the accompanying materials
    + * are made available under the terms of the Eclipse Public License v1.0
    + * which accompanies this distribution, and is available at
    + * http://www.eclipse.org/legal/epl-v10.html
    + *
    + * Contributors:
    + *     Xilinx - initial API and implementation
    + *******************************************************************************/
    +package org.eclipse.tcf.internal.debug.ui.profiler;
    +
    +import java.util.HashMap;
    +import java.util.Map;
    +
    +import org.eclipse.jface.dialogs.Dialog;
    +import org.eclipse.jface.dialogs.IDialogConstants;
    +import org.eclipse.swt.SWT;
    +import org.eclipse.swt.events.ModifyEvent;
    +import org.eclipse.swt.events.ModifyListener;
    +import org.eclipse.swt.events.SelectionEvent;
    +import org.eclipse.swt.events.SelectionListener;
    +import org.eclipse.swt.graphics.Font;
    +import org.eclipse.swt.layout.GridData;
    +import org.eclipse.swt.layout.GridLayout;
    +import org.eclipse.swt.widgets.Button;
    +import org.eclipse.swt.widgets.Composite;
    +import org.eclipse.swt.widgets.Control;
    +import org.eclipse.swt.widgets.Label;
    +import org.eclipse.swt.widgets.MessageBox;
    +import org.eclipse.swt.widgets.Shell;
    +import org.eclipse.swt.widgets.Text;
    +import org.eclipse.tcf.internal.debug.ui.ImageCache;
    +import org.eclipse.tcf.internal.debug.ui.model.TCFModel;
    +import org.eclipse.tcf.services.IProfiler;
    +
    +class ProfilerSettingsDlg extends Dialog {
    +
    +    static final String PARAM_VIEW_UPDATE_PERIOD = "ViewUpdatePeriod";
    +    static final String PARAM_AGGREGATE = "Aggregate";
    +
    +    Map conf;
    +    Map data;
    +
    +    private Button aggregate_button;
    +    private Button stack_trace_button;
    +    private Text frame_cnt_text;
    +    private Text view_update_text;
    +
    +    protected ProfilerSettingsDlg(Shell shell, Map conf) {
    +        super(shell);
    +        this.conf = conf;
    +    }
    +
    +    @Override
    +    protected void configureShell(Shell shell) {
    +        super.configureShell(shell);
    +        shell.setText("Profiler Configuration");
    +        shell.setImage(ImageCache.getImage(ImageCache.IMG_PROFILER));
    +    }
    +
    +    @Override
    +    protected void createButtonsForButtonBar(Composite parent) {
    +        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
    +        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
    +        updateButtons();
    +    }
    +
    +    @Override
    +    protected Control createDialogArea(Composite parent) {
    +        Composite composite = (Composite)super.createDialogArea(parent);
    +        createFields(composite);
    +        setData();
    +        composite.setSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
    +        return composite;
    +    }
    +
    +    private void createFields(Composite parent) {
    +        Font font = parent.getFont();
    +        Composite composite = new Composite(parent, SWT.NONE);
    +        GridLayout layout = new GridLayout(2, false);
    +        composite.setFont(font);
    +        composite.setLayout(layout);
    +        composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    +
    +        aggregate_button = new Button(composite, SWT.CHECK);
    +        aggregate_button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL, 0, true, false, 2, 1));
    +        aggregate_button.setFont(font);
    +        aggregate_button.setText("Aggregate per function");
    +
    +        stack_trace_button = new Button(composite, SWT.CHECK);
    +        stack_trace_button.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL, 0, true, false, 2, 1));
    +        stack_trace_button.setFont(font);
    +        stack_trace_button.setText("Enable stack tracing");
    +
    +        stack_trace_button.addSelectionListener(new SelectionListener() {
    +            @Override
    +            public void widgetSelected(SelectionEvent e) {
    +                updateButtons();
    +            }
    +            @Override
    +            public void widgetDefaultSelected(SelectionEvent e) {
    +                updateButtons();
    +            }
    +        });
    +
    +        Label frame_cnt_label = new Label(composite, SWT.WRAP);
    +        frame_cnt_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
    +        frame_cnt_label.setFont(font);
    +        frame_cnt_label.setText("Max stack frames count:");
    +
    +        frame_cnt_text = new Text(composite, SWT.SINGLE | SWT.BORDER);
    +        frame_cnt_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    +        frame_cnt_text.setFont(font);
    +
    +        frame_cnt_text.addModifyListener(new ModifyListener() {
    +            public void modifyText(ModifyEvent e) {
    +                updateButtons();
    +            }
    +        });
    +
    +        Label view_update_label = new Label(composite, SWT.WRAP);
    +        view_update_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
    +        view_update_label.setFont(font);
    +        view_update_label.setText("View update interval (sec):");
    +
    +        view_update_text = new Text(composite, SWT.SINGLE | SWT.BORDER);
    +        view_update_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    +        view_update_text.setFont(font);
    +
    +        view_update_text.addModifyListener(new ModifyListener() {
    +            public void modifyText(ModifyEvent e) {
    +                updateButtons();
    +            }
    +        });
    +    }
    +
    +    private void updateButtons() {
    +        Button btn = getButton(IDialogConstants.OK_ID);
    +        if (btn != null) btn.setEnabled(true);
    +        frame_cnt_text.setEnabled(stack_trace_button.getSelection());
    +    }
    +
    +    private void setData() {
    +        Boolean b = (Boolean)conf.get(PARAM_AGGREGATE);
    +        aggregate_button.setSelection(b != null && b.booleanValue());
    +        Number n = (Number)conf.get(IProfiler.PARAM_FRAME_CNT);
    +        if (n == null || n.intValue() <= 1) {
    +            stack_trace_button.setSelection(false);
    +            frame_cnt_text.setText("5");
    +        }
    +        else {
    +            stack_trace_button.setSelection(true);
    +            frame_cnt_text.setText(conf.get(IProfiler.PARAM_FRAME_CNT).toString());
    +        }
    +        view_update_text.setText(conf.get(PARAM_VIEW_UPDATE_PERIOD).toString());
    +    }
    +
    +    private void getData() {
    +        data = new HashMap();
    +        data.put(PARAM_AGGREGATE, aggregate_button.getSelection());
    +        if (stack_trace_button.getSelection()) {
    +            data.put(IProfiler.PARAM_FRAME_CNT, new Integer(frame_cnt_text.getText()));
    +        }
    +        else {
    +            data.put(IProfiler.PARAM_FRAME_CNT, 1);
    +        }
    +        data.put(PARAM_VIEW_UPDATE_PERIOD, new Integer(view_update_text.getText()));
    +    }
    +
    +    @Override
    +    protected void okPressed() {
    +        try {
    +            getData();
    +        }
    +        catch (Throwable x) {
    +            MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR | SWT.OK);
    +            mb.setText("Invalid data");
    +            mb.setMessage(TCFModel.getErrorMessage(x, true));
    +            mb.open();
    +            return;
    +        }
    +        super.okPressed();
    +    }
    +}
    diff --git a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/profiler/ProfilerView.java b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/profiler/ProfilerView.java
    index 76a972ac8..bf0b515b8 100644
    --- a/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/profiler/ProfilerView.java
    +++ b/plugins/org.eclipse.tcf.debug.ui/src/org/eclipse/tcf/internal/debug/ui/profiler/ProfilerView.java
    @@ -34,6 +34,7 @@ import org.eclipse.jface.viewers.LabelProvider;
     import org.eclipse.jface.viewers.StructuredSelection;
     import org.eclipse.jface.viewers.TableViewer;
     import org.eclipse.jface.viewers.Viewer;
    +import org.eclipse.jface.window.Window;
     import org.eclipse.swt.SWT;
     import org.eclipse.swt.events.ControlEvent;
     import org.eclipse.swt.events.ControlListener;
    @@ -75,6 +76,7 @@ import org.eclipse.tcf.services.ILineNumbers;
     import org.eclipse.tcf.services.IProfiler;
     import org.eclipse.tcf.services.ISymbols;
     import org.eclipse.tcf.util.TCFDataCache;
    +import org.eclipse.tcf.util.TCFTask;
     import org.eclipse.ui.IActionBars;
     import org.eclipse.ui.IWorkbenchWindow;
     import org.eclipse.ui.part.ViewPart;
    @@ -83,6 +85,8 @@ public class ProfilerView extends ViewPart {
     
         private static final long UPDATE_DELAY = 4000;
         private static final int FRAME_COUNT = 5;
    +    private static final String PARAM_VIEW_UPDATE_PERIOD = ProfilerSettingsDlg.PARAM_VIEW_UPDATE_PERIOD;
    +    private static final String PARAM_AGGREGATE = ProfilerSettingsDlg.PARAM_AGGREGATE;
     
         private static class ProfileSample {
             int cnt;
    @@ -95,6 +99,7 @@ public class ProfilerView extends ViewPart {
     
         private static class ProfileData {
             final String ctx;
    +        final Map params;
     
             boolean stopped;
             boolean unsupported;
    @@ -110,8 +115,11 @@ public class ProfilerView extends ViewPart {
             ProfileEntry[] entries;
     
             @SuppressWarnings("unchecked")
    -        ProfileData(String ctx, int frame_cnt) {
    +        ProfileData(String ctx, Map params) {
                 this.ctx = ctx;
    +            this.params = new HashMap(params);
    +            Number n = (Number)params.get(IProfiler.PARAM_FRAME_CNT);
    +            int frame_cnt = n.intValue();
                 map = new Map[frame_cnt];
                 for (int i = 0; i < frame_cnt; i++) {
                     map[i] = new HashMap>();
    @@ -121,6 +129,7 @@ public class ProfilerView extends ViewPart {
     
         private static class ProfileEntry {
             final BigInteger addr;
    +        final Set addr_list = new HashSet();
     
             String name;
             String file_full;
    @@ -131,6 +140,7 @@ public class ProfilerView extends ViewPart {
             ProfileEntry[] up;
             ProfileEntry[] dw;
     
    +        boolean src_info_valid;
             boolean mark;
     
             ProfileEntry(BigInteger addr) {
    @@ -264,12 +274,15 @@ public class ProfilerView extends ViewPart {
             final int sorting;
             final TCFNode selection;
             final Map entries = new HashMap();
    -        final Map funcs = new HashMap();
    +        final Map addr_to_func_addr = new HashMap();
    +        final Map addr_to_func_id = new HashMap();
             final TCFNodeExecContext node;
             final ProfileData prof_data;
             final ISymbols symbols;
             final ILineNumbers line_numbers;
    +        final boolean aggrerate;
             final int generation;
    +        TCFDataCache pending;
             boolean done;
     
             Update() {
    @@ -287,34 +300,71 @@ public class ProfilerView extends ViewPart {
                     symbols = null;
                     line_numbers = null;
                     generation = 0;
    +                aggrerate = false;
                 }
                 else {
                     node = (TCFNodeExecContext)selection;
                     symbols = node.getChannel().getRemoteService(ISymbols.class);
                     line_numbers = node.getChannel().getRemoteService(ILineNumbers.class);
                     generation = p.generation_inp;
    +                Boolean b = (Boolean)p.params.get(PARAM_AGGREGATE);
    +                aggrerate = b != null && b.booleanValue();
                 }
                 last_update = this;
             }
     
    -        private boolean getFuncName(ProfileEntry pe) {
    -            if (symbols == null) return true;
    -            String func_id = funcs.get(pe.addr);
    +        private String getFuncID(BigInteger addr) {
    +            if (symbols == null) return "";
    +            String func_id = addr_to_func_id.get(addr);
                 if (func_id == null) {
                     func_id = "";
    -                TCFDataCache func_cache = node.getFuncInfo(pe.addr);
    +                TCFDataCache func_cache = node.getFuncInfo(addr);
                     if (func_cache != null) {
    -                    if (!func_cache.validate(this)) return false;
    +                    if (!func_cache.validate()) {
    +                        pending = func_cache;
    +                        return null;
    +                    }
                         TCFFunctionRef func_data = func_cache.getData();
                         if (func_data != null && func_data.symbol_id != null) {
                             func_id = func_data.symbol_id;
                         }
                     }
    -                funcs.put(pe.addr, func_id);
    +                addr_to_func_id.put(addr, func_id);
    +            }
    +            return func_id;
    +        }
    +
    +        private BigInteger getFuncAddress(BigInteger addr) {
    +            if (!aggrerate) return addr;
    +            BigInteger func_addr = addr_to_func_addr.get(addr);
    +            if (func_addr != null) return func_addr;
    +            String func_id = getFuncID(addr);
    +            if (func_id == null) return null;
    +            func_addr = addr;
    +            if (func_id.length() > 0) {
    +                TCFDataCache sym_cache = node.getModel().getSymbolInfoCache(func_id);
    +                if (!sym_cache.validate()) {
    +                    pending = sym_cache;
    +                    return null;
    +                }
    +                ISymbols.Symbol sym_data = sym_cache.getData();
    +                if (sym_data != null && sym_data.getAddress() != null) {
    +                    func_addr = JSON.toBigInteger(sym_data.getAddress());
    +                }
                 }
    +            addr_to_func_addr.put(addr, func_addr);
    +            return func_addr;
    +        }
    +
    +        private boolean getFuncName(ProfileEntry pe) {
    +            String func_id = getFuncID(pe.addr);
    +            if (func_id == null) return false;
                 if (func_id.length() > 0) {
                     TCFDataCache sym_cache = node.getModel().getSymbolInfoCache(func_id);
    -                if (!sym_cache.validate(this)) return false;
    +                if (!sym_cache.validate()) {
    +                    pending = sym_cache;
    +                    return false;
    +                }
                     ISymbols.Symbol sym_data = sym_cache.getData();
                     if (sym_data != null && sym_data.getName() != null) {
                         pe.name = sym_data.getName();
    @@ -327,7 +377,10 @@ public class ProfilerView extends ViewPart {
                 if (line_numbers == null) return true;
                 TCFDataCache line_cache = node.getLineInfo(pe.addr);
                 if (line_cache == null) return true;
    -            if (!line_cache.validate(this)) return false;
    +            if (!line_cache.validate()) {
    +                pending = line_cache;
    +                return false;
    +            }
                 TCFSourceRef line_data = line_cache.getData();
                 if (line_data != null && line_data.area != null) {
                     pe.file_full = TCFSourceLookupParticipant.toFileName(line_data.area);
    @@ -343,29 +396,31 @@ public class ProfilerView extends ViewPart {
                 return true;
             }
     
    -        void linkEntry(ProfileEntry pe) {
    +        private void linkEntry(ProfileEntry pe) {
                 Set set_up = new HashSet();
                 Set set_dw = new HashSet();
                 for (int n = 0; n < prof_data.map.length; n++) {
    -                List s0 = prof_data.map[n].get(pe.addr);
    -                if (s0 != null) {
    -                    for (ProfileSample x : s0) {
    -                        assert x.trace[n].equals(pe.addr);
    -                        if (x.trace.length <= n + 1) continue;
    -                        BigInteger addr_up = x.trace[n + 1];
    -                        ProfileEntry pe_up = entries.get(addr_up);
    -                        set_up.add(pe_up);
    +                for (BigInteger addr : pe.addr_list) {
    +                    List s0 = prof_data.map[n].get(addr);
    +                    if (s0 != null) {
    +                        for (ProfileSample x : s0) {
    +                            assert addr.equals(x.trace[n]);
    +                            if (x.trace.length <= n + 1) continue;
    +                            BigInteger addr_up = getFuncAddress(x.trace[n + 1]);
    +                            ProfileEntry pe_up = entries.get(addr_up);
    +                            set_up.add(pe_up);
    +                        }
                         }
    -                }
    -                if (n == prof_data.map.length - 1) continue;
    -                List s1 = prof_data.map[n + 1].get(pe.addr);
    -                if (s1 != null) {
    -                    for (ProfileSample x : s1) {
    -                        assert x.trace.length > n + 1;
    -                        assert x.trace[n + 1].equals(pe.addr);
    -                        BigInteger addr_dw = x.trace[n];
    -                        ProfileEntry pe_dw = entries.get(addr_dw);
    -                        set_dw.add(pe_dw);
    +                    if (n == prof_data.map.length - 1) continue;
    +                    List s1 = prof_data.map[n + 1].get(addr);
    +                    if (s1 != null) {
    +                        for (ProfileSample x : s1) {
    +                            assert x.trace.length > n + 1;
    +                            assert addr.equals(x.trace[n + 1]);
    +                            BigInteger addr_dw = getFuncAddress(x.trace[n]);
    +                            ProfileEntry pe_dw = entries.get(addr_dw);
    +                            set_dw.add(pe_dw);
    +                        }
                         }
                     }
                 }
    @@ -373,7 +428,7 @@ public class ProfilerView extends ViewPart {
                 if (set_dw.size() > 0) pe.dw = set_dw.toArray(new ProfileEntry[set_dw.size()]);
             }
     
    -        void addUpTotal(ProfileEntry pe, float cnt) {
    +        private void addUpTotal(ProfileEntry pe, float cnt) {
                 if (cnt <= 0.1 || pe.up == null) return;
                 pe.mark = true;
                 int n = 0;
    @@ -393,6 +448,7 @@ public class ProfilerView extends ViewPart {
     
             @Override
             public void run() {
    +            pending = null;
                 if (done) return;
                 if (last_update != this) return;
                 if (prof_data != null && generation != prof_data.generation_out) {
    @@ -402,29 +458,39 @@ public class ProfilerView extends ViewPart {
                     else {
                         for (int n = 0; n < prof_data.map.length; n++) {
                             for (BigInteger addr : prof_data.map[n].keySet()) {
    -                            ProfileEntry pe = entries.get(addr);
    -                            if (pe != null) continue;
    -                            pe = new ProfileEntry(addr);
    -                            if (!getFuncName(pe)) return;
    -                            if (!getLineInfo(pe)) return;
    -                            if (n == 0) {
    -                                List s = prof_data.map[0].get(addr);
    -                                for (ProfileSample x : s) pe.count += x.cnt;
    +                            BigInteger func_addr = getFuncAddress(addr);
    +                            if (func_addr == null) continue;
    +                            ProfileEntry pe = entries.get(func_addr);
    +                            if (pe == null) {
    +                                pe = new ProfileEntry(func_addr);
    +                                entries.put(pe.addr, pe);
    +                            }
    +                            if (!pe.addr_list.contains(addr)) {
    +                                if (n == 0) {
    +                                    List s = prof_data.map[0].get(addr);
    +                                    for (ProfileSample x : s) pe.count += x.cnt;
    +                                }
    +                                pe.addr_list.add(addr);
    +                            }
    +                            if (!pe.src_info_valid) {
    +                                pe.src_info_valid = true;
    +                                if (!getFuncName(pe)) pe.src_info_valid = false;
    +                                if (!getLineInfo(pe)) pe.src_info_valid = false;
                                 }
    -                            entries.put(pe.addr, pe);
                             }
                         }
    -                    for (ProfileEntry pe : entries.values()) {
    -                        linkEntry(pe);
    +                    if (pending != null) {
    +                        pending.wait(this);
    +                        return;
                         }
    +                    for (ProfileEntry pe : entries.values()) linkEntry(pe);
                         for (List lps : prof_data.map[0].values()) {
                             for (ProfileSample ps : lps) {
                                 int n = 0;
                                 while (n < ps.trace.length) {
    -                                ProfileEntry pe = entries.get(ps.trace[n]);
    -                                if (n == ps.trace.length - 1) {
    -                                    addUpTotal(pe, ps.cnt);
    -                                }
    +                                BigInteger func_addr = getFuncAddress(ps.trace[n]);
    +                                ProfileEntry pe = entries.get(func_addr);
    +                                if (n == ps.trace.length - 1) addUpTotal(pe, ps.cnt);
                                     pe.total += ps.cnt;
                                     n++;
                                 }
    @@ -435,10 +501,12 @@ public class ProfilerView extends ViewPart {
                             if (pe.dw != null) Arrays.sort(pe.dw, new SampleComparator(2));
                         }
                     }
    -                ProfileEntry[] arr = entries.values().toArray(new ProfileEntry[entries.size()]);
    -                Arrays.sort(arr, new SampleComparator(sorting));
                     prof_data.generation_out = generation;
    -                prof_data.entries = arr;
    +                prof_data.entries = entries.values().toArray(new ProfileEntry[entries.size()]);
    +                assert pending == null;
    +            }
    +            if (prof_data != null && prof_data.entries != null) {
    +                Arrays.sort(prof_data.entries, new SampleComparator(sorting));
                 }
                 done = true;
                 final boolean enable_start =
    @@ -454,26 +522,25 @@ public class ProfilerView extends ViewPart {
                 parent.getDisplay().asyncExec(new Runnable() {
                     @Override
                     public void run() {
    +                    if (parent.isDisposed()) return;
                         action_start.setEnabled(enable_start);
                         action_stop.setEnabled(enable_stop);
                         profile_node = node;
                         Object viewer_input = prof_data != null ? prof_data.entries : null;
    -                    if (viewer_main.getInput() != viewer_input) {
    -                        ISelection s = viewer_main.getSelection();
    -                        ProfilerView.this.sample_count = sample_count;
    -                        viewer_main.setInput(viewer_input);
    -                        if (s instanceof IStructuredSelection) {
    -                            IStructuredSelection ss = (IStructuredSelection)s;
    -                            List l = new ArrayList();
    -                            for (Object obj : ss.toArray()) {
    -                                if (obj instanceof ProfileEntry) {
    -                                    ProfileEntry pe = (ProfileEntry)obj;
    -                                    pe = entries.get(pe.addr);
    -                                    if (pe != null) l.add(pe);
    -                                }
    +                    ISelection s = viewer_main.getSelection();
    +                    ProfilerView.this.sample_count = sample_count;
    +                    viewer_main.setInput(viewer_input);
    +                    if (s instanceof IStructuredSelection) {
    +                        IStructuredSelection ss = (IStructuredSelection)s;
    +                        List l = new ArrayList();
    +                        for (Object obj : ss.toArray()) {
    +                            if (obj instanceof ProfileEntry) {
    +                                ProfileEntry pe = (ProfileEntry)obj;
    +                                pe = entries.get(pe.addr);
    +                                if (pe != null) l.add(pe);
                                 }
    -                            setSelection(l, false);
                             }
    +                        setSelection(l, false);
                         }
                         if (!enable_start) {
                             status.setText("Selected context does not support profiling");
    @@ -550,13 +617,26 @@ public class ProfilerView extends ViewPart {
         private final Action action_start = new Action("Start", ImageCache.getImageDescriptor(ImageCache.IMG_THREAD_RUNNNIG)) {
             @Override
             public void run() {
    -            Protocol.invokeLater(new Runnable() {
    +            final TCFNode node = selection;
    +            if (node == null) return;
    +            Map conf = new TCFTask>() {
                     @Override
                     public void run() {
    -                    if (selection == null) return;
    -                    start(selection);
    +                    done(getConfiguration(node.getID()));
                     }
    -            });
    +            }.getE();
    +            ProfilerSettingsDlg dlg = new ProfilerSettingsDlg(getSite().getShell(), conf);
    +            if (dlg.open() == Window.OK) {
    +                final Map params = dlg.data;
    +                Protocol.invokeLater(new Runnable() {
    +                    @Override
    +                    public void run() {
    +                        configuration.put(node.getID(), params);
    +                        if (selection != node) return;
    +                        start(selection);
    +                    }
    +                });
    +            }
             }
         };
     
    @@ -605,6 +685,9 @@ public class ProfilerView extends ViewPart {
             60
         };
     
    +    private final Map> configuration =
    +            new HashMap>();
    +
         @Override
         public void createPartControl(Composite parent) {
             this.parent = parent;
    @@ -944,18 +1027,27 @@ public class ProfilerView extends ViewPart {
             viewer_main.getControl().setFocus();
         }
     
    -    public void start(TCFNode node) {
    +    private Map getConfiguration(String ctx) {
    +        Map params = configuration.get(ctx);
    +        if (params == null) {
    +            params = new HashMap();
    +            params.put(IProfiler.PARAM_FRAME_CNT, FRAME_COUNT);
    +            params.put(PARAM_VIEW_UPDATE_PERIOD, 4);
    +            configuration.put(ctx,  params);
    +        }
    +        return params;
    +    }
    +
    +    private void start(TCFNode node) {
             assert Protocol.isDispatchThread();
             if (!launch_listener_ok) {
                 TCFModelManager.getModelManager().addListener(launch_listener);
                 launch_listener_ok = true;
             }
    -        Map params = new HashMap();
    -        params.put(IProfiler.PARAM_FRAME_CNT, FRAME_COUNT);
    -        configure(node, params);
    +        configure(node, getConfiguration(node.getID()));
         }
     
    -    public void stop(TCFNode node) {
    +    private void stop(TCFNode node) {
             assert Protocol.isDispatchThread();
             Map params = new HashMap();
             configure(node, params);
    @@ -975,8 +1067,7 @@ public class ProfilerView extends ViewPart {
                                 if (d != null) d.stopped = true;
                             }
                             else {
    -                            Number n = (Number)params.get(IProfiler.PARAM_FRAME_CNT);
    -                            ProfileData d = new ProfileData(node.getID(), n.intValue());
    +                            ProfileData d = new ProfileData(node.getID(), params);
                                 if (m == null) data.put(node.getModel(), m = new HashMap());
                                 m.put(d.ctx, d);
                             }
    @@ -1044,6 +1135,7 @@ public class ProfilerView extends ViewPart {
         }
     
         private void addSample(ProfileData p, BigInteger[] trace, int len, int cnt) {
    +        assert len > 0;
             p.sample_count += cnt;
             p.generation_inp++;
             ProfileSample ps = null;
    -- 
    cgit v1.2.3