Added tracing support to Protobuf Editor.
Change-Id: Ie4be4fb412b3bf7e9d77d74beecc91a255286960
diff --git a/com.google.eclipse.protobuf.ui/.options b/com.google.eclipse.protobuf.ui/.options
new file mode 100644
index 0000000..e05b026
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/.options
@@ -0,0 +1,7 @@
+# Debugging options for the com.google.eclipse.protobuf plugin.
+
+# Turns on debugging for the com.google.eclipse.protobuf plugin.
+com.google.eclipse.protobuf.ui/debug=false
+
+# Turns on debugging for com.google.eclipse.protobuf.scoping.
+com.google.eclipse.protobuf.ui/scoping=false
diff --git a/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF b/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF
index 09ab499..096c09d 100644
--- a/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF
+++ b/com.google.eclipse.protobuf.ui/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
Bundle-Name: %Bundle-Name
Bundle-Vendor: %Bundle-Vendor
Bundle-Version: 2.2.1.qualifier
-Bundle-Activator: com.google.eclipse.protobuf.ui.internal.ProtobufActivator
+Bundle-Activator: com.google.eclipse.protobuf.ui.internal.Activator
Bundle-SymbolicName: com.google.eclipse.protobuf.ui; singleton:=true
Bundle-ActivationPolicy: lazy
Require-Bundle: com.google.eclipse.protobuf,
diff --git a/com.google.eclipse.protobuf.ui/plugin.xml b/com.google.eclipse.protobuf.ui/plugin.xml
index 3570fe6..4f55fd7 100644
--- a/com.google.eclipse.protobuf.ui/plugin.xml
+++ b/com.google.eclipse.protobuf.ui/plugin.xml
@@ -278,4 +278,15 @@
<extension point="org.eclipse.xtext.ui.shared.overridingGuiceModule">
<module class="com.google.eclipse.protobuf.ui.SharedModuleOverrides"/>
</extension>
+ <extension
+ point="org.eclipse.ui.trace.traceComponents">
+ <component
+ id="com.google.eclipse.protobuf.ui.trace"
+ label="%trace.component.label">
+ <bundle
+ consumed="false"
+ name="com.google.eclipse.protobuf.ui">
+ </bundle>
+ </component>
+ </extension>
</plugin>
diff --git a/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/internal/Activator.java b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/internal/Activator.java
new file mode 100644
index 0000000..21da6ee
--- /dev/null
+++ b/com.google.eclipse.protobuf.ui/src/com/google/eclipse/protobuf/ui/internal/Activator.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 Google Inc.
+ *
+ * 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
+ */
+package com.google.eclipse.protobuf.ui.internal;
+
+import java.util.Hashtable;
+
+import org.eclipse.osgi.service.debug.DebugOptions;
+import org.eclipse.osgi.service.debug.DebugOptionsListener;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+import com.google.eclipse.protobuf.util.Tracer;
+
+/**
+ * The activator class controls the plug-in life cycle.
+ *
+ * @author atrookey@google.com (Alexander Rookey)
+ */
+public class Activator extends ProtobufActivator {
+ private ServiceRegistration<DebugOptionsListener> debugOptionsListener;
+
+ @Override
+ public void start(BundleContext bundleContext) throws Exception {
+ Hashtable<String, String> props = new Hashtable<>(4);
+ props.put(DebugOptions.LISTENER_SYMBOLICNAME, "com.google.eclipse.protobuf.ui");
+ debugOptionsListener =
+ bundleContext.registerService(
+ DebugOptionsListener.class, Tracer.RESOURCES_DEBUG_OPTIONS_LISTENER, props);
+ super.start(bundleContext);
+ }
+
+ @Override
+ public void stop(BundleContext bundleContext) throws Exception {
+ try {
+ debugOptionsListener.unregister();
+ } finally {
+ super.stop(bundleContext);
+ }
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
index e9d8556..3b82c45 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/scoping/ProtobufScopeProvider.java
@@ -1,14 +1,16 @@
/*
- * Copyright (c) 2011 Google Inc.
+ * Copyright (c) 2016 Google Inc.
*
- * 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
- *
+ * 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
*/
package com.google.eclipse.protobuf.scoping;
import static com.google.eclipse.protobuf.scoping.OptionType.typeOf;
+import static com.google.eclipse.protobuf.util.Tracer.DEBUG_SCOPING;
+import static com.google.eclipse.protobuf.validation.ProtobufResourceValidator.getScopeProviderTimingCollector;
import static java.util.Collections.emptySet;
import com.google.eclipse.protobuf.model.util.MessageFields;
@@ -62,9 +64,11 @@
*
* @author alruiz@google.com (Alex Ruiz)
*
- * @see <a href="http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping">Xtext Scoping</a>
+ * @see <a href="http://www.eclipse.org/Xtext/documentation/latest/xtext.html#scoping">Xtext
+ * Scoping</a>
*/
-public class ProtobufScopeProvider extends AbstractDeclarativeScopeProvider implements ScopeProvider {
+public class ProtobufScopeProvider extends AbstractDeclarativeScopeProvider
+ implements ScopeProvider {
private static final boolean DO_NOT_IGNORE_CASE = false;
@Inject private ComplexTypeFinderStrategy complexTypeFinderDelegate;
@@ -83,6 +87,18 @@
@Inject private NativeOptionDescriptions nativeOptionDescriptions;
@Inject private Options options;
+ @Override
+ public IScope getScope(EObject context, EReference reference) {
+ if (DEBUG_SCOPING) {
+ getScopeProviderTimingCollector().startTimer();
+ }
+ IScope scope = super.getScope(context, reference);
+ if (DEBUG_SCOPING) {
+ getScopeProviderTimingCollector().stopTimer();
+ }
+ return scope;
+ }
+
@SuppressWarnings("unused")
public IScope scope_ComplexTypeLink_target(ComplexTypeLink link, EReference r) {
EObject c = link.eContainer();
@@ -100,7 +116,8 @@
return createEmptyScope();
}
- @Override public Collection<IEObjectDescription> potentialComplexTypesFor(MessageField field) {
+ @Override
+ public Collection<IEObjectDescription> potentialComplexTypesFor(MessageField field) {
return modelElementFinder.find(field, complexTypeFinderDelegate, ComplexType.class);
}
@@ -112,7 +129,8 @@
return createScope(extensibleTypes);
}
- @Override public Collection<IEObjectDescription> potentialExtensibleTypesFor(TypeExtension extension) {
+ @Override
+ public Collection<IEObjectDescription> potentialExtensibleTypesFor(TypeExtension extension) {
Protobuf root = modelObjects.rootOf(extension);
return modelElementFinder.find(root, complexTypeFinderDelegate, ExtensibleType.class);
}
@@ -124,12 +142,14 @@
return createScope(messages);
}
- @Override public Collection<IEObjectDescription> potentialMessagesFor(Rpc rpc) {
+ @Override
+ public Collection<IEObjectDescription> potentialMessagesFor(Rpc rpc) {
Protobuf root = modelObjects.rootOf(rpc);
return allMessages(root);
}
- @Override public Collection<IEObjectDescription> potentialMessagesFor(Stream stream) {
+ @Override
+ public Collection<IEObjectDescription> potentialMessagesFor(Stream stream) {
Protobuf root = modelObjects.rootOf(stream);
return allMessages(root);
}
@@ -184,9 +204,10 @@
EObject container = c.eContainer();
if (container instanceof Group) {
OptionType optionType = OptionType.findOptionTypeForLevelOf(container.eContainer());
- return createScope(optionType != null
- ? modelElementFinder.find(option, customOptionFinderDelegate, optionType)
- : Collections.<IEObjectDescription>emptySet());
+ return createScope(
+ optionType != null
+ ? modelElementFinder.find(option, customOptionFinderDelegate, optionType)
+ : Collections.<IEObjectDescription>emptySet());
}
}
@@ -196,7 +217,8 @@
return createScope(descriptions);
}
- @Override public Collection<IEObjectDescription> potentialSourcesFor(AbstractCustomOption option) {
+ @Override
+ public Collection<IEObjectDescription> potentialSourcesFor(AbstractCustomOption option) {
OptionType optionType = typeOf((AbstractOption) option);
Collection<IEObjectDescription> descriptions = emptySet();
if (optionType != null) {
@@ -225,11 +247,13 @@
return emptySet();
}
- @Override public Collection<IEObjectDescription> potentialMessageFieldsFor(AbstractCustomOption option) {
+ @Override
+ public Collection<IEObjectDescription> potentialMessageFieldsFor(AbstractCustomOption option) {
return customOptionFieldFinder.findOptionFields(option, messageFieldFinderDelegate);
}
- @Override public Collection<IEObjectDescription> potentialExtensionFieldsFor(AbstractCustomOption option) {
+ @Override
+ public Collection<IEObjectDescription> potentialExtensionFieldsFor(AbstractCustomOption option) {
return customOptionFieldFinder.findOptionFields(option, extensionFieldFinderDelegate);
}
@@ -260,12 +284,15 @@
return null;
}
- @Override public Collection<IEObjectDescription> potentialNormalFieldNames(ComplexValue value) {
+ @Override
+ public Collection<IEObjectDescription> potentialNormalFieldNames(ComplexValue value) {
return customOptionFieldNameFinder.findFieldNamesSources(value, normalFieldNameFinderDelegate);
}
- @Override public Collection<IEObjectDescription> potentialExtensionFieldNames(ComplexValue value) {
- return customOptionFieldNameFinder.findFieldNamesSources(value, extensionFieldNameFinderDelegate);
+ @Override
+ public Collection<IEObjectDescription> potentialExtensionFieldNames(ComplexValue value) {
+ return customOptionFieldNameFinder.findFieldNamesSources(
+ value, extensionFieldNameFinderDelegate);
}
private static IScope createEmptyScope() {
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/TimingCollector.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/TimingCollector.java
new file mode 100644
index 0000000..3f79477
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/TimingCollector.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016 Google Inc.
+ *
+ * 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
+ */
+package com.google.eclipse.protobuf.util;
+
+public class TimingCollector {
+ private long invocationCount;
+ private long sum;
+ private long time;
+
+ public double getAverageInMilliseconds() {
+ return sum * 1.e-6 / invocationCount;
+ }
+
+ public long getInvocationCount() {
+ return invocationCount;
+ }
+
+ public void startTimer() {
+ time = System.nanoTime();
+ }
+
+ public void stopTimer() {
+ sum += System.nanoTime() - time;
+ invocationCount++;
+ }
+
+ public void clear() {
+ invocationCount = 0;
+ sum = 0;
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "Invocation Count: %1$d Mean Duration: %2$fms",
+ getInvocationCount(),
+ getAverageInMilliseconds());
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Tracer.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Tracer.java
new file mode 100644
index 0000000..474b1bd
--- /dev/null
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/util/Tracer.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2016 Google Inc.
+ *
+ * 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
+ */
+package com.google.eclipse.protobuf.util;
+
+import org.eclipse.osgi.service.debug.DebugOptions;
+import org.eclipse.osgi.service.debug.DebugOptionsListener;
+import org.eclipse.osgi.service.debug.DebugTrace;
+
+/**
+ * The debugging related arguments for the protobuf editor.
+ *
+ * @author atrookey@google.com (Alexander Rookey)
+ */
+public class Tracer {
+ public static DebugTrace trace;
+ public static boolean DEBUG_SCOPING = false;
+ public static final String TRACE_PREFIX = "[Google Protobuf Editor] ";
+
+ public static final DebugOptionsListener RESOURCES_DEBUG_OPTIONS_LISTENER =
+ new DebugOptionsListener() {
+ @Override
+ public void optionsChanged(DebugOptions options) {
+ if (trace == null) {
+ trace = options.newDebugTrace("com.google.eclipse.protobuf.ui");
+ }
+ boolean debug = options.getBooleanOption("com.google.eclipse.protobuf.ui/debug", false);
+ DEBUG_SCOPING =
+ debug && options.getBooleanOption("com.google.eclipse.protobuf.ui/scoping", false);
+ }
+ };
+
+ /**
+ * Prints a trace message to standard output.
+ */
+ public static void trace(String message) {
+ System.out.println(TRACE_PREFIX + message);
+ }
+}
diff --git a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java
index a33d0ec..969e2ba 100644
--- a/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java
+++ b/com.google.eclipse.protobuf/src/com/google/eclipse/protobuf/validation/ProtobufResourceValidator.java
@@ -1,9 +1,9 @@
/*
- * Copyright (c) 2011 Google Inc.
+ * Copyright (c) 2016 Google Inc.
*
- * 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
- *
+ * 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
*/
package com.google.eclipse.protobuf.validation;
@@ -15,6 +15,8 @@
import static org.eclipse.xtext.validation.CheckMode.KEY;
import static org.eclipse.xtext.validation.CheckType.FAST;
import static org.eclipse.xtext.validation.impl.ConcreteSyntaxEValidator.DISABLE_CONCRETE_SYNTAX_EVALIDATOR;
+import static com.google.eclipse.protobuf.util.Tracer.DEBUG_SCOPING;
+import static com.google.eclipse.protobuf.util.Tracer.trace;
import static com.google.common.collect.Lists.newArrayListWithExpectedSize;
import static com.google.common.collect.Maps.newHashMap;
@@ -38,6 +40,7 @@
import org.eclipse.xtext.validation.ResourceValidatorImpl;
import com.google.eclipse.protobuf.linking.ProtobufDiagnostic;
+import com.google.eclipse.protobuf.util.TimingCollector;
/**
* Adds support for converting scoping errors into warnings if non-proto2 files are imported.
@@ -46,14 +49,32 @@
*/
public class ProtobufResourceValidator extends ResourceValidatorImpl {
private static final Logger log = Logger.getLogger(ProtobufResourceValidator.class);
+ private static final ThreadLocal<TimingCollector> scopeProviderTimingCollector =
+ new ThreadLocal<TimingCollector>() {
+ @Override
+ public TimingCollector initialValue() {
+ return new TimingCollector();
+ }
+ };
- @Override public List<Issue> validate(Resource resource, CheckMode mode, CancelIndicator indicator) {
+ @Override
+ public List<Issue> validate(Resource resource, CheckMode mode, CancelIndicator indicator) {
CancelIndicator monitor = indicator == null ? CancelIndicator.NullImpl : indicator;
+ getScopeProviderTimingCollector().clear();
resolveProxies(resource, monitor);
+ if (DEBUG_SCOPING) {
+ trace("Debugging AbstractDeclarativeScopeProvider.getScope() "
+ + getScopeProviderTimingCollector().toString());
+ }
+ return handleIssues(resource, mode, monitor);
+ }
+
+ private List<Issue> handleIssues(Resource resource, CheckMode mode, CancelIndicator monitor) {
if (monitor.isCanceled()) {
return null;
}
- List<Issue> result = newArrayListWithExpectedSize(resource.getErrors().size() + resource.getWarnings().size());
+ List<Issue> result =
+ newArrayListWithExpectedSize(resource.getErrors().size() + resource.getWarnings().size());
try {
IAcceptor<Issue> acceptor = createAcceptor(result);
Status status = delegateValidationToDiagnostician(resource, mode, monitor, acceptor);
@@ -76,14 +97,15 @@
return result;
}
- private Status delegateValidationToDiagnostician(Resource resource, CheckMode mode,
- CancelIndicator monitor, IAcceptor<Issue> acceptor) {
+ private Status delegateValidationToDiagnostician(
+ Resource resource, CheckMode mode, CancelIndicator monitor, IAcceptor<Issue> acceptor) {
Status hasNonProto2Import = Status.OK;
for (EObject element : resource.getContents()) {
if (monitor.isCanceled()) {
return Status.CANCELED;
}
- Diagnostic diagnostic = getDiagnostician().validate(element, validationOptions(resource, mode, monitor));
+ Diagnostic diagnostic =
+ getDiagnostician().validate(element, validationOptions(resource, mode, monitor));
if (convertIssuesToMarkers(acceptor, diagnostic) == Status.PROTO1_IMPORTS_FOUND) {
hasNonProto2Import = Status.PROTO1_IMPORTS_FOUND;
}
@@ -91,7 +113,8 @@
return hasNonProto2Import;
}
- private Map<Object, Object> validationOptions(Resource resource, CheckMode mode, CancelIndicator monitor) {
+ private Map<Object, Object> validationOptions(
+ Resource resource, CheckMode mode, CancelIndicator monitor) {
Map<Object, Object> options = newHashMap();
options.put(KEY, mode);
options.put(CANCEL_INDICATOR, monitor);
@@ -118,7 +141,10 @@
return hasNonProto2Import;
}
- private Status createErrors(Resource resource, boolean proto1ImportsFound, IAcceptor<Issue> acceptor,
+ private Status createErrors(
+ Resource resource,
+ boolean proto1ImportsFound,
+ IAcceptor<Issue> acceptor,
CancelIndicator monitor) {
for (Resource.Diagnostic error : resource.getErrors()) {
if (monitor.isCanceled()) {
@@ -154,7 +180,8 @@
return false;
}
- private Status createWarnings(Resource resource, IAcceptor<Issue> acceptor, CancelIndicator monitor) {
+ private Status createWarnings(
+ Resource resource, IAcceptor<Issue> acceptor, CancelIndicator monitor) {
for (Resource.Diagnostic warning : resource.getWarnings()) {
if (monitor.isCanceled()) {
return Status.CANCELED;
@@ -165,7 +192,9 @@
}
private static enum Status {
- OK, CANCELED, PROTO1_IMPORTS_FOUND;
+ OK,
+ CANCELED,
+ PROTO1_IMPORTS_FOUND;
boolean hasProto1Imports() {
return (this == PROTO1_IMPORTS_FOUND);
@@ -175,4 +204,8 @@
return (this == CANCELED);
}
}
-}
\ No newline at end of file
+
+ public static TimingCollector getScopeProviderTimingCollector() {
+ return scopeProviderTimingCollector.get();
+ }
+}