Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug 63620] Fix GUI freeze when viewing response body with long lines #694

Merged
merged 2 commits into from
Feb 13, 2022

Conversation

vlsi
Copy link
Collaborator

@vlsi vlsi commented Jan 17, 2022

GUI gets unresponsive when the response contains long lines (e.g lines exceeding 100K chars).
The workaround is to add artificial line breaks.

https://bz.apache.org/bugzilla/show_bug.cgi?id=63620

We try to break on word boundaries first, and if not possible,
we break on char boundaries (e.g. large chunks of base64 data).

view.results.tree.max_line_size=110000 (defaults to 110K)
view.results.tree.soft_wrap_line_size=100000 (defaults to max_line_size/1.1)

For the reference, using zero-width space does not solve the problem, so I use \n for breaking lines.

CPU spin trace looks as follows:

"AWT-EventQue...
...
        at sun.font.GlyphLayout.layout(Unknown Source)
...
        at java.awt.font.TextLine.<init>(Unknown Source)
        at java.awt.font.TextMeasurer.makeTextLineOnRange(Unknown Source)
        at java.awt.font.TextMeasurer.getLayout(Unknown Source)
...
        at javax.swing.text.JTextComponent.setDocument(Unknown Source)
        at org.apache.jmeter.visualizers.SamplerResultTab.setTextOptimized(SamplerResultTab.java:695)
...

@vlsi vlsi force-pushed the split_text branch 6 times, most recently from 6af6f78 to dd9e05f Compare January 17, 2022 09:58
@codecov-commenter
Copy link

codecov-commenter commented Jan 17, 2022

Codecov Report

Merging #694 (d4f6371) into master (755302a) will decrease coverage by 0.04%.
The diff coverage is 35.89%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #694      +/-   ##
============================================
- Coverage     55.59%   55.54%   -0.05%     
- Complexity    10336    10345       +9     
============================================
  Files          1059     1061       +2     
  Lines         65053    65209     +156     
  Branches       7401     7432      +31     
============================================
+ Hits          36163    36221      +58     
- Misses        26340    26431      +91     
- Partials       2550     2557       +7     
Impacted Files Coverage Δ
.../jmeter/visualizers/RenderAsBoundaryExtractor.java 2.43% <0.00%> (-0.04%) ⬇️
...g/apache/jmeter/visualizers/RenderAsCssJQuery.java 1.85% <0.00%> (-0.02%) ⬇️
.../org/apache/jmeter/visualizers/RenderAsRegexp.java 2.35% <0.00%> (-0.03%) ⬇️
...a/org/apache/jmeter/visualizers/RenderAsXPath.java 5.88% <0.00%> (-0.06%) ⬇️
.../org/apache/jmeter/visualizers/RenderAsXPath2.java 3.49% <0.00%> (-0.03%) ⬇️
...rg/apache/jmeter/visualizers/SamplerResultTab.java 32.35% <0.00%> (-0.20%) ⬇️
...c/core/src/main/java/org/apache/jmeter/JMeter.java 38.62% <0.00%> (-0.11%) ⬇️
...va/org/apache/jorphan/gui/ui/KerningOptimizer.java 0.00% <0.00%> (ø)
.../org/apache/jorphan/gui/ui/TextAreaUIWithUndo.java 0.00% <0.00%> (ø)
.../jmeter/visualizers/ViewResultsFullVisualizer.java 40.54% <40.00%> (-0.02%) ⬇️
... and 2 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 755302a...d4f6371. Read the comment docs.

@vlsi vlsi changed the title [Bug 63620] Fix GUI freeze when viewing response body with long line breaks [Bug 63620] Fix GUI freeze when viewing response body with long lines Jan 17, 2022
@vlsi vlsi force-pushed the split_text branch 2 times, most recently from 34d45af to 17a050d Compare January 17, 2022 10:26
@vlsi vlsi force-pushed the split_text branch 2 times, most recently from 455a2cc to cb8a120 Compare January 24, 2022 16:59
@FSchumacher
Copy link
Contributor

Looks really good to me. What keeps you from merging?

@vlsi
Copy link
Collaborator Author

vlsi commented Jan 31, 2022

Thank you for the review and for yet another test case.

my setup: macOS Monterey 12.1, Java 11.0.13.

With Nimbus LaF it is really fast when browsing "view results tree".
However, with DarkLaf, there are multi-second delays switching to longer texts (~15 which corresponds to 884'736 chars)

It is still usable, so we might want to merge the change and investigate the slowness with Darklaf later, however, I don't quite understand why Darklaf is slower since the thread spends time in DarkTextUI.getPreferredSize(DarkTextUI.java:223) which just calls super.getPreferredSize(c).

It might be the font selected by Darklaf is somehow slower.
I did try using different "hard wrap lengths" (including 80 where all the lines are fully visible in the UI and there's no horizontal scroll, however, it did not improve the performance.

Here's a stacktrace:

"AWT-EventQueue-0" #21 prio=6 os_prio=31 cpu=69414,09ms elapsed=117,36s tid=0x000000014f405800 nid=0xd903 runnable  [0x0000000291d8f000]
   java.lang.Thread.State: RUNNABLE
	at sun.font.SunLayoutEngine.shape([email protected]/Native Method)
	at sun.font.SunLayoutEngine.layout([email protected]/SunLayoutEngine.java:198)
	at sun.font.GlyphLayout$EngineRecord.layout([email protected]/GlyphLayout.java:687)
	at sun.font.GlyphLayout.layout([email protected]/GlyphLayout.java:468)
	at sun.font.ExtendedTextSourceLabel.createGV([email protected]/ExtendedTextSourceLabel.java:329)
	at sun.font.ExtendedTextSourceLabel.getGV([email protected]/ExtendedTextSourceLabel.java:315)
	at sun.font.ExtendedTextSourceLabel.createLogicalBounds([email protected]/ExtendedTextSourceLabel.java:225)
	at sun.font.ExtendedTextSourceLabel.getAdvance([email protected]/ExtendedTextSourceLabel.java:134)
	at java.awt.font.TextLine.init([email protected]/TextLine.java:281)
	at java.awt.font.TextLine.<init>([email protected]/TextLine.java:129)
	at java.awt.font.TextLine.fastCreateTextLine([email protected]/TextLine.java:978)
	at java.awt.font.TextLayout.fastInit([email protected]/TextLayout.java:611)
	at java.awt.font.TextLayout.<init>([email protected]/TextLayout.java:392)
	at java.awt.Font.getStringBounds([email protected]/Font.java:2616)
	at sun.swing.SwingUtilities2.getFontCharsWidth([email protected]/SwingUtilities2.java:958)
	at sun.swing.SwingUtilities2.getFontCharWidth([email protected]/SwingUtilities2.java:946)
	at javax.swing.text.Utilities.getTabbedTextOffset([email protected]/Utilities.java:537)
	at javax.swing.text.Utilities.getTabbedTextOffset([email protected]/Utilities.java:466)
	at javax.swing.text.WrappedPlainView.calculateBreakPosition([email protected]/WrappedPlainView.java:366)
	at javax.swing.text.WrappedPlainView$WrappedLine.breakLines([email protected]/WrappedPlainView.java:920)
	at javax.swing.text.WrappedPlainView$WrappedLine.getPreferredSpan([email protected]/WrappedPlainView.java:692)
	at javax.swing.text.BoxView.calculateMajorAxisRequirements([email protected]/BoxView.java:873)
	at javax.swing.text.BoxView.checkRequests([email protected]/BoxView.java:931)
	at javax.swing.text.BoxView.setSpanOnAxis([email protected]/BoxView.java:330)
	at javax.swing.text.BoxView.layout([email protected]/BoxView.java:710)
	at javax.swing.text.BoxView.setSize([email protected]/BoxView.java:398)
	at javax.swing.text.WrappedPlainView.setSize([email protected]/WrappedPlainView.java:519)
	at javax.swing.plaf.basic.BasicTextUI$RootView.setSize([email protected]/BasicTextUI.java:1818)
	at javax.swing.plaf.basic.BasicTextUI.getPreferredSize([email protected]/BasicTextUI.java:948)
	at com.github.weisj.darklaf.ui.text.DarkTextUI.getPreferredSize(DarkTextUI.java:223)
	at javax.swing.JComponent.getPreferredSize([email protected]/JComponent.java:1680)
	at javax.swing.JEditorPane.getPreferredSize([email protected]/JEditorPane.java:1345)
	at javax.swing.JViewport.getViewSize([email protected]/JViewport.java:1119)
	at javax.swing.plaf.basic.BasicScrollPaneUI.syncScrollPaneWithViewport([email protected]/BasicScrollPaneUI.java:330)
	at javax.swing.plaf.basic.BasicScrollPaneUI$Handler.stateChanged([email protected]/BasicScrollPaneUI.java:1126)
	at javax.swing.JViewport.fireStateChanged([email protected]/JViewport.java:1490)
	at javax.swing.JViewport.setView([email protected]/JViewport.java:1089)
	at javax.swing.JScrollPane.setViewportView([email protected]/JScrollPane.java:980)
	at org.apache.jmeter.visualizers.RenderAsText.showTextResponse(RenderAsText.java:36)
	at org.apache.jmeter.visualizers.RenderAsText.renderResult(RenderAsText.java:29)
	at org.apache.jmeter.visualizers.ViewResultsFullVisualizer.valueChanged(ViewResultsFullVisualizer.java:400)
	at org.apache.jmeter.visualizers.ViewResultsFullVisualizer.valueChanged(ViewResultsFullVisualizer.java:373)
	at javax.swing.JTree.fireValueChanged([email protected]/JTree.java:2967)
	at javax.swing.JTree$TreeSelectionRedirector.valueChanged([email protected]/JTree.java:3456)
	at javax.swing.tree.DefaultTreeSelectionModel.fireValueChanged([email protected]/DefaultTreeSelectionModel.java:641)
	at javax.swing.tree.DefaultTreeSelectionModel.notifyPathChange([email protected]/DefaultTreeSelectionModel.java:1111)
	at javax.swing.tree.DefaultTreeSelectionModel.setSelectionPaths([email protected]/DefaultTreeSelectionModel.java:297)
	at javax.swing.tree.DefaultTreeSelectionModel.setSelectionPath([email protected]/DefaultTreeSelectionModel.java:191)
	at javax.swing.JTree.setSelectionPath([email protected]/JTree.java:1656)

/cc @weisJ

@weisJ
Copy link
Contributor

weisJ commented Feb 2, 2022

I suspect the performance hit is coming from font kerning. Try to set the font to comp.setFont(comp.getFont().derive(Collections.singletonMap(TextAttribute.KERNING, 0)))

@vlsi
Copy link
Collaborator Author

vlsi commented Feb 3, 2022

@weisJ , thanks for the hint. Initially, I thought the issue was ligature-related, however, ligatures are disabled by default. I completely forgot about the kerning.

As I deactivated kerning the UI became much better, and the delays are like ~1sec when displaying 10MiB.


On my machine, the kerning becomes noticeable at 9 and 10 scales (10-20KiB), so I am inclined to either completely disable the kerning for the results tab or automatically disable it after a certain threshold (e.g. after 10KiB).

@sginsbourg
Copy link

sginsbourg commented Feb 5, 2022 via email

@vlsi
Copy link
Collaborator Author

vlsi commented Feb 5, 2022

Which setting?

@sginsbourg
Copy link

sginsbourg commented Feb 5, 2022 via email

@vlsi
Copy link
Collaborator Author

vlsi commented Feb 5, 2022

The idea is to disable kerning for long texts by default

@sginsbourg
Copy link

sginsbourg commented Feb 5, 2022 via email

@vlsi
Copy link
Collaborator Author

vlsi commented Feb 6, 2022

Just in case you wonder, here's a sample from macOS with hi-DPI screen. The first line is with kerning enabled, and the second one is with deactivated kerning.

jmeter kerning sample

@vlsi
Copy link
Collaborator Author

vlsi commented Feb 6, 2022

RSyntaxTextArea is not always compatible with dynamic kerning :-/

javax.swing.text.BadLocationException: Position not represented by view
        at org.fife.ui.rsyntaxtextarea.WrappedSyntaxView.modelToView(WrappedSyntaxView.java:770)
        at java.desktop/javax.swing.plaf.basic.BasicTextUI$RootView.modelToView(BasicTextUI.java:1605)
        at java.desktop/javax.swing.plaf.basic.BasicTextUI.modelToView(BasicTextUI.java:1110)
        at java.desktop/javax.swing.plaf.basic.BasicTextUI.modelToView(BasicTextUI.java:1087)
        at java.desktop/javax.swing.plaf.basic.BasicTextUI.modelToView(BasicTextUI.java:1063)
        at java.desktop/javax.swing.text.JTextComponent.modelToView(JTextComponent.java:1392)
        at org.fife.ui.rtextarea.RTextAreaBase.possiblyUpdateCurrentLineHighlightLocation(RTextAreaBase.java:754)
        at org.fife.ui.rtextarea.RTextArea.fireCaretUpdate(RTextArea.java:611)
        at org.fife.ui.rsyntaxtextarea.RSyntaxTextArea.fireCaretUpdate(RSyntaxTextArea.java:874)
        at org.fife.ui.rtextarea.RTextAreaBase.forceCurrentLineHighlightRepaint(RTextAreaBase.java:310)
        at org.fife.ui.rsyntaxtextarea.RSyntaxTextArea.setFont(RSyntaxTextArea.java:2601)
        at org.apache.jorphan.gui.ui.KerningOptimizer.configureKerning(KerningOptimizer.java:50)
        at org.apache.jorphan.gui.ui.KerningOptimizer$DisableKerningForLargeTexts.changedUpdate(KerningOptimizer.java:90)
        at java.desktop/javax.swing.text.AbstractDocument.fireChangedUpdate(AbstractDocument.java:232)
        at org.fife.ui.rsyntaxtextarea.RSyntaxDocument.updateLastTokensBelow(RSyntaxDocument.java:618)
        at org.fife.ui.rsyntaxtextarea.RSyntaxDocument.fireRemoveUpdate(RSyntaxDocument.java:253)
        at java.desktop/javax.swing.text.AbstractDocument.handleRemove(AbstractDocument.java:628)
        at java.desktop/javax.swing.text.AbstractDocument.remove(AbstractDocument.java:596)
        at java.desktop/javax.swing.text.AbstractDocument.replace(AbstractDocument.java:672)
        at java.desktop/javax.swing.text.JTextComponent.setText(JTextComponent.java:1729)
        at org.apache.jmeter.gui.util.JSyntaxTextArea.setInitialText(JSyntaxTextArea.java:296)
        at org.apache.jmeter.visualizers.RequestViewRaw.clearData(RequestViewRaw.java:82)
        at org.apache.jmeter.visualizers.RequestPanel.clearData(RequestPanel.java:105)
        at org.apache.jmeter.visualizers.SamplerResultTab.clearData(SamplerResultTab.java:215)
        at org.apache.jmeter.visualizers.SamplerResultTab.setupTabPane(SamplerResultTab.java:235)
        at org.apache.jmeter.visualizers.ViewResultsFullVisualizer.valueChanged(ViewResultsFullVisualizer.java:395)
        at org.apache.jmeter.visualizers.ViewResultsFullVisualizer.valueChanged(ViewResultsFullVisualizer.java:373)
        at java.desktop/javax.swing.JTree.fireValueChanged(JTree.java:2967)
        at java.desktop/javax.swing.JTree$TreeSelectionRedirector.valueChanged(JTree.java:3456)
        at java.desktop/javax.swing.tree.DefaultTreeSelectionModel.fireValueChanged(DefaultTreeSelectionModel.java:641)
        at java.desktop/javax.swing.tree.DefaultTreeSelectionModel.notifyPathChange(DefaultTreeSelectionModel.java:1111)
        at java.desktop/javax.swing.tree.DefaultTreeSelectionModel.setSelectionPaths(DefaultTreeSelectionModel.java:297)
        at java.desktop/javax.swing.tree.DefaultTreeSelectionModel.setSelectionPath(DefaultTreeSelectionModel.java:191)
        at java.desktop/javax.swing.JTree.setSelectionPath(JTree.java:1656)
        at java.desktop/javax.swing.plaf.basic.BasicTreeUI.selectPathForEvent(BasicTreeUI.java:2736)
        at java.desktop/javax.swing.plaf.basic.BasicTreeUI$Handler.handleSelection(BasicTreeUI.java:4016)
        at java.desktop/javax.swing.plaf.basic.BasicTreeUI$Handler.mousePressed(BasicTreeUI.java:3955)
        at java.desktop/java.awt.AWTEventMulticaster.mousePressed(AWTEventMulticaster.java:287)
        at java.desktop/java.awt.Component.processMouseEvent(Component.java:6632)
        at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3342)
        at java.desktop/java.awt.Component.processEvent(Component.java:6400)
        at java.desktop/java.awt.Container.processEvent(Container.java:2263)
        at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5011)
        at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
        at java.desktop/java.awt.Component.dispatchEvent(Component.java:4843)
        at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
        at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4544)

@vlsi
Copy link
Collaborator Author

vlsi commented Feb 6, 2022

I've added a feature to automatically disable kerning when text length exceeds 10K, and now I can click through all the results.

vlsi added 2 commits February 13, 2022 13:01
GUI gets unresponsive when the response contains long lines (e.g lines exceeding 100K chars).
The workaround is to add artificial line breaks.

We try to break on word boundaries first, and if not possible,
we break on char boundaries (e.g. large chunks of base64 data).

view.results.tree.max_line_size=110000 (defaults to 110K)
view.results.tree.soft_wrap_line_size=100000 (defaults to max_line_size/1.1)

CPU spin trace looks as follows:

"AWT-EventQue...
...
        at sun.font.GlyphLayout.layout(Unknown Source)
...
        at java.awt.font.TextLine.<init>(Unknown Source)
        at java.awt.font.TextMeasurer.makeTextLineOnRange(Unknown Source)
        at java.awt.font.TextMeasurer.getLayout(Unknown Source)
...
        at javax.swing.text.JTextComponent.setDocument(Unknown Source)
        at org.apache.jmeter.visualizers.SamplerResultTab.setTextOptimized(SamplerResultTab.java:695)
...
The treshold can be configured via text.kerning.max_document_size
@vlsi vlsi merged commit d4f6371 into apache:master Feb 13, 2022
@gurudattgd04
Copy link

Im using macos and 5.5 version - If i click on View Results tree when the request sent has body like 5k/10k records then the UI is getting frozen. Not sure if this fix covers this use case too ? @vlsi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants