From c14fc8a4bf50c0768c4f337876d6ed7ee78e8478 Mon Sep 17 00:00:00 2001 From: Lars Vogel Date: Wed, 2 Sep 2026 15:45:23 +0200 Subject: [PATCH] Add a Build Monitor view showing build time per builder and project MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finding the builder that makes a build slow requires starting Eclipse with -debug and reading the performance log. The new org.eclipse.ui.buildmonitor bundle contributes a view that lists the run count, total time and slowest run of each builder per project. It switches builder tracing on while it is open and restores the previous debug options when it closes. The view only shows data once builder tracing can be toggled at runtime, which is what the builder tracing change provides. Assisted-by: multiple AI agents and layers of automated tooling 🤖 --- .../org.eclipse.ui.buildmonitor/.classpath | 7 + .../org.eclipse.ui.buildmonitor/.project | 34 +++ .../org.eclipse.core.resources.prefs | 2 + .../.settings/org.eclipse.core.runtime.prefs | 2 + .../.settings/org.eclipse.jdt.core.prefs | 141 ++++++++++++ .../.settings/org.eclipse.jdt.ui.prefs | 151 +++++++++++++ .../META-INF/MANIFEST.MF | 14 ++ .../org.eclipse.ui.buildmonitor/about.html | 36 ++++ .../build.properties | 21 ++ .../plugin.properties | 16 ++ .../org.eclipse.ui.buildmonitor/plugin.xml | 13 ++ .../buildmonitor/BuildMonitorView.java | 203 ++++++++++++++++++ .../internal/buildmonitor/BuilderTiming.java | 57 +++++ .../ui/internal/buildmonitor/Messages.java | 36 ++++ .../internal/buildmonitor/Messages.properties | 23 ++ 15 files changed, 756 insertions(+) create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/.classpath create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/.project create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.resources.prefs create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.runtime.prefs create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.core.prefs create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.ui.prefs create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/META-INF/MANIFEST.MF create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/about.html create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/build.properties create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/plugin.properties create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/plugin.xml create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuildMonitorView.java create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuilderTiming.java create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.java create mode 100644 resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.properties diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.classpath b/resources/bundles/org.eclipse.ui.buildmonitor/.classpath new file mode 100644 index 00000000000..375961e4d61 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.project b/resources/bundles/org.eclipse.ui.buildmonitor/.project new file mode 100644 index 00000000000..05164c25817 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.project @@ -0,0 +1,34 @@ + + + org.eclipse.ui.buildmonitor + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.resources.prefs b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..99f26c0203a --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=UTF-8 diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.runtime.prefs b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.runtime.prefs new file mode 100644 index 00000000000..5a0ad22d2a7 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.core.runtime.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +line.separator=\n diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.core.prefs b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..70bb1eec7b3 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,141 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.builder.cleanOutputFolder=clean +org.eclipse.jdt.core.builder.duplicateResourceTask=warning +org.eclipse.jdt.core.builder.invalidClasspath=abort +org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore +org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch +org.eclipse.jdt.core.circularClasspath=error +org.eclipse.jdt.core.classpath.exclusionPatterns=enabled +org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnull.secondary= +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary= +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullable.secondary= +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=21 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=21 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.doc.comment.support=enabled +org.eclipse.jdt.core.compiler.maxProblemPerUnit=100 +org.eclipse.jdt.core.compiler.problem.APILeak=warning +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=error +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=error +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=error +org.eclipse.jdt.core.compiler.problem.emptyStatement=error +org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning +org.eclipse.jdt.core.compiler.problem.fallthroughCase=error +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error +org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=error +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error +org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=disabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled +org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=protected +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error +org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public +org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag +org.eclipse.jdt.core.compiler.problem.missingJavadocTags=ignore +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled +org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=protected +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=error +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=error +org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=error +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=error +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning +org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled +org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedImport=error +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=error +org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error +org.eclipse.jdt.core.compiler.release=enabled +org.eclipse.jdt.core.compiler.source=21 +org.eclipse.jdt.core.compiler.taskCaseSensitive=enabled +org.eclipse.jdt.core.compiler.taskPriorities=NORMAL,NORMAL +org.eclipse.jdt.core.compiler.taskTags=TODO,XXX +org.eclipse.jdt.core.incompatibleJDKLevel=ignore +org.eclipse.jdt.core.incompleteClasspath=error diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.ui.prefs b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..83308cb79e5 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,151 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +internal.default.compliance=user +org.eclipse.jdt.ui.ignorelowercasenames=true +org.eclipse.jdt.ui.importorder=java;javax;org;com; +org.eclipse.jdt.ui.ondemandthreshold=99 +org.eclipse.jdt.ui.staticondemandthreshold=99 +org.eclipse.jdt.ui.text.custom_code_templates= +sp_cleanup.add_all=false +sp_cleanup.add_default_serial_version_id=false +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.also_simplify_lambda=true +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.array_with_curly=false +sp_cleanup.arrays_fill=false +sp_cleanup.bitwise_conditional_expression=false +sp_cleanup.boolean_literal=false +sp_cleanup.boolean_value_rather_than_comparison=true +sp_cleanup.break_loop=false +sp_cleanup.collection_cloning=false +sp_cleanup.comparing_on_criteria=false +sp_cleanup.comparison_statement=false +sp_cleanup.controlflow_merge=false +sp_cleanup.convert_functional_interfaces=true +sp_cleanup.convert_to_enhanced_for_loop=true +sp_cleanup.convert_to_enhanced_for_loop_if_loop_var_used=true +sp_cleanup.convert_to_switch_expressions=false +sp_cleanup.correct_indentation=false +sp_cleanup.do_while_rather_than_while=false +sp_cleanup.double_negation=false +sp_cleanup.else_if=false +sp_cleanup.embedded_if=false +sp_cleanup.evaluate_nullable=false +sp_cleanup.extract_increment=false +sp_cleanup.format_source_code=true +sp_cleanup.format_source_code_changes_only=true +sp_cleanup.hash=false +sp_cleanup.if_condition=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.instanceof=false +sp_cleanup.instanceof_keyword=false +sp_cleanup.invert_equals=false +sp_cleanup.join=false +sp_cleanup.lazy_logical_operator=false +sp_cleanup.make_local_variable_final=true +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.map_cloning=false +sp_cleanup.merge_conditional_blocks=false +sp_cleanup.multi_catch=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.no_string_creation=false +sp_cleanup.no_super=false +sp_cleanup.number_suffix=false +sp_cleanup.objects_equals=false +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.one_if_rather_than_duplicate_blocks_that_fall_through=false +sp_cleanup.operand_factorization=false +sp_cleanup.organize_imports=true +sp_cleanup.overridden_assignment=false +sp_cleanup.overridden_assignment_move_decl=true +sp_cleanup.plain_replacement=false +sp_cleanup.precompile_regex=false +sp_cleanup.primitive_comparison=false +sp_cleanup.primitive_parsing=false +sp_cleanup.primitive_rather_than_wrapper=true +sp_cleanup.primitive_serialization=false +sp_cleanup.pull_out_if_from_if_else=false +sp_cleanup.pull_up_assignment=false +sp_cleanup.push_down_negation=false +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=true +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.reduce_indentation=false +sp_cleanup.redundant_comparator=false +sp_cleanup.redundant_falling_through_block_end=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_modifiers=false +sp_cleanup.remove_redundant_semicolons=true +sp_cleanup.remove_redundant_type_arguments=true +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_array_creation=false +sp_cleanup.remove_unnecessary_casts=true +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_method_parameters=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.replace_deprecated_calls=false +sp_cleanup.return_expression=false +sp_cleanup.simplify_lambda_expression_and_method_ref=true +sp_cleanup.single_used_field=false +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.standard_comparison=false +sp_cleanup.static_inner_class=false +sp_cleanup.strictly_equal_or_different=false +sp_cleanup.stringbuffer_to_stringbuilder=false +sp_cleanup.stringbuilder=false +sp_cleanup.stringbuilder_for_local_vars=true +sp_cleanup.stringconcat_stringbuffer_stringbuilder=false +sp_cleanup.stringconcat_to_textblock=false +sp_cleanup.substring=false +sp_cleanup.switch=false +sp_cleanup.system_property=false +sp_cleanup.system_property_boolean=false +sp_cleanup.system_property_file_encoding=false +sp_cleanup.system_property_file_separator=false +sp_cleanup.system_property_line_separator=false +sp_cleanup.system_property_path_separator=false +sp_cleanup.ternary_operator=false +sp_cleanup.try_with_resource=false +sp_cleanup.unlooped_while=false +sp_cleanup.unreachable_block=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_autoboxing=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_directly_map_method=false +sp_cleanup.use_lambda=true +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_string_is_blank=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_unboxing=false +sp_cleanup.use_var=false +sp_cleanup.useless_continue=false +sp_cleanup.useless_return=false +sp_cleanup.valueof_rather_than_instantiation=false diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/META-INF/MANIFEST.MF b/resources/bundles/org.eclipse.ui.buildmonitor/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..142cb00a605 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.ui.buildmonitor; singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui;bundle-version="[3.208.0,4.0.0)", + org.eclipse.core.runtime;bundle-version="[3.35.0,4.0.0)" +Import-Package: org.eclipse.osgi.service.debug;version="[1.2.0,2.0.0)" +Bundle-ActivationPolicy: lazy +Bundle-RequiredExecutionEnvironment: JavaSE-21 +Export-Package: org.eclipse.ui.internal.buildmonitor;x-internal:=true +Automatic-Module-Name: org.eclipse.ui.buildmonitor diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/about.html b/resources/bundles/org.eclipse.ui.buildmonitor/about.html new file mode 100644 index 00000000000..164f781a8fd --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/about.html @@ -0,0 +1,36 @@ + + + + +About + + +

About This Content

+ +

November 30, 2017

+

License

+ +

+ The Eclipse Foundation makes available all content in this plug-in + ("Content"). Unless otherwise indicated below, the Content + is provided to you under the terms and conditions of the Eclipse + Public License Version 2.0 ("EPL"). A copy of the EPL is + available at http://www.eclipse.org/legal/epl-2.0. + For purposes of the EPL, "Program" will mean the Content. +

+ +

+ If you did not receive this Content directly from the Eclipse + Foundation, the Content is being redistributed by another party + ("Redistributor") and different terms and conditions may + apply to your use of any object code in the Content. Check the + Redistributor's license that was provided with the Content. If no such + license exists, contact the Redistributor. Unless otherwise indicated + below, the terms and conditions of the EPL still apply to any source + code in the Content and such source code may be obtained at http://www.eclipse.org. +

+ + + \ No newline at end of file diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/build.properties b/resources/bundles/org.eclipse.ui.buildmonitor/build.properties new file mode 100644 index 00000000000..b2b2c17ae83 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/build.properties @@ -0,0 +1,21 @@ +############################################################################### +# Copyright (c) 2026 Vogella GmbH and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Vogella GmbH - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.properties,\ + plugin.xml,\ + about.html +src.includes = about.html diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/plugin.properties b/resources/bundles/org.eclipse.ui.buildmonitor/plugin.properties new file mode 100644 index 00000000000..74c9b4da915 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/plugin.properties @@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2026 Vogella GmbH and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Vogella GmbH - initial API and implementation +############################################################################### +pluginName=Build Monitor +providerName=Eclipse.org +BuildMonitorView.name=Build Monitor diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/plugin.xml b/resources/bundles/org.eclipse.ui.buildmonitor/plugin.xml new file mode 100644 index 00000000000..4ddf564d3a5 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/plugin.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuildMonitorView.java b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuildMonitorView.java new file mode 100644 index 00000000000..a08a5673f15 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuildMonitorView.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2026 Vogella GmbH and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Vogella GmbH - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.buildmonitor; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import org.eclipse.core.runtime.PerformanceStats; +import org.eclipse.core.runtime.PerformanceStats.PerformanceListener; +import org.eclipse.core.runtime.ServiceCaller; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.viewers.ArrayContentProvider; +import org.eclipse.jface.viewers.ColumnLabelProvider; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.TableViewerColumn; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.viewers.ViewerComparator; +import org.eclipse.osgi.service.debug.DebugOptions; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Table; +import org.eclipse.ui.part.ViewPart; + +/** + * Shows how much time each builder spends on each project. Builder tracing is + * switched on while the view is open and the previous debug options are put back + * when it closes. + */ +public class BuildMonitorView extends ViewPart { + + /** Performance event fired once per builder run by org.eclipse.core.resources. */ + private static final String EVENT_BUILDERS = "org.eclipse.core.resources/perf/builders"; //$NON-NLS-1$ + + private static final String OPTION_PERF = "org.eclipse.core.runtime/perf"; //$NON-NLS-1$ + private static final String OPTION_PERF_SUCCESS = "org.eclipse.core.runtime/perf/success"; //$NON-NLS-1$ + + /** + * The options this view turns on, global flag first. A builder threshold of 0 + * reports every run to listeners without writing any of them to the log. + */ + private static final Map TRACING_OPTIONS = new LinkedHashMap<>(); + static { + TRACING_OPTIONS.put(OPTION_PERF, "true"); //$NON-NLS-1$ + TRACING_OPTIONS.put(OPTION_PERF_SUCCESS, "true"); //$NON-NLS-1$ + TRACING_OPTIONS.put(EVENT_BUILDERS, "0"); //$NON-NLS-1$ + } + + private final Map timings = new LinkedHashMap<>(); + private final Map replacedOptions = new LinkedHashMap<>(); + private boolean debugWasEnabled; + + private TableViewer viewer; + + private final PerformanceListener performanceListener = new PerformanceListener() { + @Override + public void eventFailed(PerformanceStats event, long duration) { + // unlike eventsOccurred, these events carry the project as their context + if (EVENT_BUILDERS.equals(event.getEvent())) { + record(event.getBlameString(), event.getContext(), duration); + } + } + }; + + @Override + public void createPartControl(Composite parent) { + viewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL); + Table table = viewer.getTable(); + table.setHeaderVisible(true); + table.setLinesVisible(true); + + addColumn(Messages.BuildMonitorView_builder_column, 260, BuilderTiming::getBuilder); + addColumn(Messages.BuildMonitorView_project_column, 160, BuilderTiming::getProject); + addColumn(Messages.BuildMonitorView_runs_column, 60, t -> Integer.toString(t.getRuns())); + addColumn(Messages.BuildMonitorView_total_time_column, 90, t -> Long.toString(t.getTotalTime())); + addColumn(Messages.BuildMonitorView_slowest_run_column, 90, t -> Long.toString(t.getSlowestRun())); + + viewer.setContentProvider(ArrayContentProvider.getInstance()); + viewer.setComparator(new ViewerComparator() { + @Override + public int compare(Viewer v, Object e1, Object e2) { + return Long.compare(((BuilderTiming) e2).getTotalTime(), ((BuilderTiming) e1).getTotalTime()); + } + }); + viewer.setInput(new BuilderTiming[0]); + + Action clear = new Action(Messages.BuildMonitorView_clear_action) { + @Override + public void run() { + synchronized (timings) { + timings.clear(); + } + refresh(); + } + }; + clear.setToolTipText(Messages.BuildMonitorView_clear_action_tooltip); + getViewSite().getActionBars().getToolBarManager().add(clear); + + if (enableTracing()) { + PerformanceStats.addListener(performanceListener); + setContentDescription(Messages.BuildMonitorView_tracing_enabled); + } else { + setContentDescription(Messages.BuildMonitorView_tracing_unavailable); + } + } + + @Override + public void dispose() { + PerformanceStats.removeListener(performanceListener); + disableTracing(); + super.dispose(); + } + + @Override + public void setFocus() { + viewer.getControl().setFocus(); + } + + private void addColumn(String header, int width, Function text) { + TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE); + column.getColumn().setText(header); + column.getColumn().setWidth(width); + column.setLabelProvider(new ColumnLabelProvider() { + @Override + public String getText(Object element) { + return text.apply((BuilderTiming) element); + } + }); + } + + /** + * Turns builder tracing on, remembering the previous state so that + * {@link #disableTracing()} can put it back. Returns whether the debug options + * service was available. + */ + private boolean enableTracing() { + return ServiceCaller.callOnce(getClass(), DebugOptions.class, options -> { + debugWasEnabled = options.isDebugEnabled(); + for (String option : TRACING_OPTIONS.keySet()) { + replacedOptions.put(option, options.getOption(option)); + } + options.setDebugEnabled(true); + TRACING_OPTIONS.forEach(options::setOption); + }); + } + + private void disableTracing() { + ServiceCaller.callOnce(getClass(), DebugOptions.class, options -> { + if (!debugWasEnabled) { + // disabling debug discards all options, including the ones set above + options.setDebugEnabled(false); + return; + } + replacedOptions.forEach((option, value) -> { + if (value == null) { + options.removeOption(option); + } else { + options.setOption(option, value); + } + }); + }); + } + + /** + * Called from the performance stats job, not the user interface thread. + */ + private void record(String builder, String project, long duration) { + String key = builder + '/' + project; + synchronized (timings) { + timings.computeIfAbsent(key, k -> new BuilderTiming(builder, project)).addRun(duration); + } + refresh(); + } + + private void refresh() { + Table table = viewer.getTable(); + if (table.isDisposed()) { + return; + } + table.getDisplay().asyncExec(() -> { + if (table.isDisposed()) { + return; + } + List rows; + synchronized (timings) { + rows = new ArrayList<>(timings.values()); + } + viewer.setInput(rows.toArray(new BuilderTiming[0])); + }); + } +} diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuilderTiming.java b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuilderTiming.java new file mode 100644 index 00000000000..b582e2855a6 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/BuilderTiming.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2026 Vogella GmbH and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Vogella GmbH - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.buildmonitor; + +/** + * Accumulated build times of one builder on one project. + */ +class BuilderTiming { + + private final String builder; + private final String project; + private int runs; + private long totalTime; + private long slowestRun; + + BuilderTiming(String builder, String project) { + this.builder = builder; + this.project = project; + } + + void addRun(long duration) { + runs++; + totalTime += duration; + slowestRun = Math.max(slowestRun, duration); + } + + String getBuilder() { + return builder; + } + + String getProject() { + return project; + } + + int getRuns() { + return runs; + } + + long getTotalTime() { + return totalTime; + } + + long getSlowestRun() { + return slowestRun; + } +} diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.java b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.java new file mode 100644 index 00000000000..26af14a9176 --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2026 Vogella GmbH and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Vogella GmbH - initial API and implementation + *******************************************************************************/ +package org.eclipse.ui.internal.buildmonitor; + +import org.eclipse.osgi.util.NLS; + +final class Messages extends NLS { + public static String BuildMonitorView_builder_column; + public static String BuildMonitorView_clear_action; + public static String BuildMonitorView_clear_action_tooltip; + public static String BuildMonitorView_project_column; + public static String BuildMonitorView_runs_column; + public static String BuildMonitorView_slowest_run_column; + public static String BuildMonitorView_total_time_column; + public static String BuildMonitorView_tracing_enabled; + public static String BuildMonitorView_tracing_unavailable; + + private Messages() { + // Do not instantiate. + } + + static { + NLS.initializeMessages(Messages.class.getName(), Messages.class); + } +} diff --git a/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.properties b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.properties new file mode 100644 index 00000000000..35b3da71e5e --- /dev/null +++ b/resources/bundles/org.eclipse.ui.buildmonitor/src/org/eclipse/ui/internal/buildmonitor/Messages.properties @@ -0,0 +1,23 @@ +############################################################################### +# Copyright (c) 2026 Vogella GmbH and others. +# +# This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Vogella GmbH - initial API and implementation +############################################################################### + +BuildMonitorView_builder_column=Builder +BuildMonitorView_clear_action=Clear +BuildMonitorView_clear_action_tooltip=Discards the collected build times +BuildMonitorView_project_column=Project +BuildMonitorView_runs_column=Runs +BuildMonitorView_slowest_run_column=Slowest (ms) +BuildMonitorView_total_time_column=Total (ms) +BuildMonitorView_tracing_enabled=Builder tracing is on while this view is open. +BuildMonitorView_tracing_unavailable=Tracing is unavailable, the debug options service was not found.