thSoft / elysium

LilyPond IDE for Eclipse
http://elysium.thsoft.hu
14 stars 3 forks source link

Long-Running Include Checks when Deleting Resources #136

Closed david-pace closed 6 years ago

david-pace commented 6 years ago

I have a workspace with 31 projects, some of which contain LilyPond files. When I try to delete folders inside my projects recursively, the UI shows the message "Checking Preconditions..." and it takes a long time until the deletion is initiated. For example, I deleted a folder containing 47 files and three subfolders containing 8 files each (71 files total), which took about 1 minute to check the preconditions before the actual deletion started.

I discovered that the corresponding thread tries to resolve LilyPond imports, which seems to be quite expensive. Apparently this is done for each pair of LilyPond file in my workspace and file to be deleted. The stack looks similar to this one when the thread is suspended:

Thread [ModalContext] (Suspended)   
    owns: LilyPondValueConverterService  (id=258)   
    BasicEObjectImpl$2(AbstractTreeIterator<E>).next() line: 139    
    EcoreUtil2$1.next() line: 247   
    EcoreUtil2$1.next() line: 1 
    GrammarUtil.collectAllRules(Grammar, Set<AbstractRule>, Set<AbstractRule>, Set<String>, Set<Grammar>) line: 372 
    GrammarUtil.allRules(Grammar) line: 349 
    GrammarUtil.allParserRules(Grammar) line: 392   
    LilyPondValueConverterService(AbstractDeclarativeValueConverterService).registerEFactoryConverters(Map<String,IValueConverter<Object>>) line: 206   
    LilyPondValueConverterService(AbstractDeclarativeValueConverterService).internalRegisterForClass(Class<?>, Map<String,IValueConverter<Object>>) line: 115   
    LilyPondValueConverterService(AbstractDeclarativeValueConverterService).getConverters() line: 100   
    LilyPondValueConverterService(AbstractDeclarativeValueConverterService).getConverter(String) line: 88   
    LilyPondValueConverterService(AbstractDeclarativeValueConverterService).toValue(String, String, INode) line: 79 
    DefaultEcoreElementFactory.getTokenValue(Object, String, INode) line: 90    
    DefaultEcoreElementFactory.set(EObject, String, Object, String, INode) line: 69 
    InternalLilyPondParser(AbstractInternalAntlrParser).set(EObject, String, Object, String, INode) line: 327   
    InternalLilyPondParser(AbstractInternalAntlrParser).setWithLastConsumed(EObject, String, Object, String) line: 338  
    InternalLilyPondParser.ruleVersion() line: 4073 
    InternalLilyPondParser.ruleSpecialCommand() line: 3437  
    InternalLilyPondParser.ruleCommand() line: 1791 
    InternalLilyPondParser.ruleCommonExpression() line: 683 
    InternalLilyPondParser.ruleExpression() line: 446   
    InternalLilyPondParser.ruleLilyPond() line: 265 
    InternalLilyPondParser.entryRuleLilyPond() line: 182    
    GeneratedMethodAccessor51.invoke(Object, Object[]) line: not available  
    DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43  
    Method.invoke(Object, Object...) line: 498  
    InternalLilyPondParser(AbstractInternalAntlrParser).parse(String) line: 549 
    LilyPondParser(AbstractAntlrParser).doParse(String, CharStream, NodeModelBuilder, int) line: 102    
    LilyPondParser(AbstractAntlrParser).parse(String, CharStream) line: 84  
    LilyPondParser(AbstractAntlrParser).doParse(Reader) line: 62    
    LilyPondParser(AbstractParser).parse(Reader) line: 33   
    LazyLinkingResource(XtextResource).doLoad(InputStream, Map<?,?>) line: 170  
    LazyLinkingResource.doLoad(InputStream, Map<?,?>) line: 100 
    LazyLinkingResource(ResourceImpl).load(InputStream, Map<?,?>) line: 1518    
    LazyLinkingResource(ResourceImpl).load(Map<?,?>) line: 1297 
    ResourceSetImpl.demandLoad(Resource) line: 259  
    ResourceSetImpl.demandLoadHelper(Resource) line: 274    
    ResourceSetImpl.getResource(URI, boolean) line: 406 
    RefactoringSupport.getIncludes(IFile, IFile) line: 70   
    RefactoringSupport$4.visit(IResource) line: 198 
    Resource$2.visit(IResourceProxy) line: 120  
    Resource$1.visitElement(ElementTree, IPathRequestor, Object) line: 84   
    ElementTreeIterator.doIteration(DataTreeNode, IElementContentVisitor) line: 82  
    ElementTreeIterator.doIteration(DataTreeNode, IElementContentVisitor) line: 87  
    ElementTreeIterator.doIteration(DataTreeNode, IElementContentVisitor) line: 87  
    ElementTreeIterator.iterate(IElementContentVisitor) line: 122   
    WorkspaceRoot(Resource).accept(IResourceProxyVisitor, int, int) line: 94    
    WorkspaceRoot(Resource).accept(IResourceProxyVisitor, int) line: 52 
    WorkspaceRoot(Resource).accept(IResourceVisitor, int, int) line: 117    
    WorkspaceRoot(Resource).accept(IResourceVisitor) line: 105  
    RefactoringSupport.checkConditions(IFile) line: 193 
    DeleteFolderParticipant$1.visit(IResource) line: 40 
    Resource$2.visit(IResourceProxy) line: 120  
    Resource$1.visitElement(ElementTree, IPathRequestor, Object) line: 84   
    ElementTreeIterator.doIteration(DataTreeNode, IElementContentVisitor) line: 82  
    ElementTreeIterator.doIteration(DataTreeNode, IElementContentVisitor) line: 87  
    ElementTreeIterator.doIteration(DataTreeNode, IElementContentVisitor) line: 87  
    ElementTreeIterator.iterate(IElementContentVisitor) line: 129   
    Folder(Resource).accept(IResourceProxyVisitor, int, int) line: 94   
    Folder(Resource).accept(IResourceProxyVisitor, int) line: 52    
    Folder(Resource).accept(IResourceVisitor, int, int) line: 117   
    Folder(Resource).accept(IResourceVisitor) line: 105 
    DeleteFolderParticipant.checkConditions(IProgressMonitor, CheckConditionsContext) line: 35  
    DeleteRefactoring(ProcessorBasedRefactoring).checkFinalConditions(IProgressMonitor) line: 255   
    CheckConditionsOperation.run(IProgressMonitor) line: 83 
    CreateChangeOperation.run(IProgressMonitor) line: 119   
    UIPerformChangeOperation(PerformChangeOperation).run(IProgressMonitor) line: 207    
    Workspace.run(ICoreRunnable, ISchedulingRule, int, IProgressMonitor) line: 2240 
    Workspace.run(IWorkspaceRunnable, ISchedulingRule, int, IProgressMonitor) line: 2267    
    WorkbenchRunnableAdapter.run(IProgressMonitor) line: 86 
    ModalContext$ModalContextThread.run() line: 119 

The crucial aspect is that this is also performed if the folders to be deleted contain no LilyPond files at all. In the above example, my folders containied 47 CSV files, 24 DOT files and 24 PDF files.

Things to be checked:

I am aware that the include logics and parser performance are currently optimized, however I think that in this case additional performance can be achieved by logical skipping of unnecessary include checks.

nittka commented 6 years ago

Could you tell me which version you had installed for the above performance measurements. The recent release should already contains improvements for refactoring performance (see #118). This does not mean that I won't consider this ticket when going over the refactoring code once more.

david-pace commented 6 years ago

Thank you for the feedback. The measurements were made with Elysium 0.5.2.201508091006. I will try to update (this did not work for me so far due to #135) and will report whether the operation performs faster.

nittka commented 6 years ago

I did not comment on #135 because I could not reproduce the update problem. Both with a regular installation and an Eclipse market place installation the Elysium update site was present... Please try a separate new installation with 0.5.3 (note that it has a Score view performance issue, we are currently working on).

david-pace commented 6 years ago

I just tested with version 0.5.3.201802071711 and the precondition checks are performed considerably faster. The deletion of the same folder in the same workspace now starts nearly instantly. From the usability perspective, this issue could therefore be closed. It is up to you if you want to leave it open for refactoring logics optimization. Thanks!

nittka commented 6 years ago

I included a reminder in the refactoring ticket and will close this one.