Skip to content

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

Merged
vlsi merged 2 commits into
apache:masterfrom
vlsi:split_text
Feb 13, 2022
Merged

vlsi merged 2 commits into
apache:masterfrom
vlsi:split_text

Conversation

@vlsi

@vlsi vlsi commented Jan 17, 2022 •

Copy link
Copy Markdown
Collaborator

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

codecov-commenter commented Jan 17, 2022 •

Copy link
Copy Markdown

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
Comment thread src/jorphan/src/main/java/org/apache/jorphan/util/StringWrap.java Outdated
Comment thread xdocs/usermanual/properties_reference.xml Outdated
@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
Copy Markdown
Contributor

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

@vlsi

vlsi commented Jan 31, 2022

Copy link
Copy Markdown
Collaborator Author

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(java.desktop@11.0.13/Native Method)
	at sun.font.SunLayoutEngine.layout(java.desktop@11.0.13/SunLayoutEngine.java:198)
	at sun.font.GlyphLayout$EngineRecord.layout(java.desktop@11.0.13/GlyphLayout.java:687)
	at sun.font.GlyphLayout.layout(java.desktop@11.0.13/GlyphLayout.java:468)
	at sun.font.ExtendedTextSourceLabel.createGV(java.desktop@11.0.13/ExtendedTextSourceLabel.java:329)
	at sun.font.ExtendedTextSourceLabel.getGV(java.desktop@11.0.13/ExtendedTextSourceLabel.java:315)
	at sun.font.ExtendedTextSourceLabel.createLogicalBounds(java.desktop@11.0.13/ExtendedTextSourceLabel.java:225)
	at sun.font.ExtendedTextSourceLabel.getAdvance(java.desktop@11.0.13/ExtendedTextSourceLabel.java:134)
	at java.awt.font.TextLine.init(java.desktop@11.0.13/TextLine.java:281)
	at java.awt.font.TextLine.<init>(java.desktop@11.0.13/TextLine.java:129)
	at java.awt.font.TextLine.fastCreateTextLine(java.desktop@11.0.13/TextLine.java:978)
	at java.awt.font.TextLayout.fastInit(java.desktop@11.0.13/TextLayout.java:611)
	at java.awt.font.TextLayout.<init>(java.desktop@11.0.13/TextLayout.java:392)
	at java.awt.Font.getStringBounds(java.desktop@11.0.13/Font.java:2616)
	at sun.swing.SwingUtilities2.getFontCharsWidth(java.desktop@11.0.13/SwingUtilities2.java:958)
	at sun.swing.SwingUtilities2.getFontCharWidth(java.desktop@11.0.13/SwingUtilities2.java:946)
	at javax.swing.text.Utilities.getTabbedTextOffset(java.desktop@11.0.13/Utilities.java:537)
	at javax.swing.text.Utilities.getTabbedTextOffset(java.desktop@11.0.13/Utilities.java:466)
	at javax.swing.text.WrappedPlainView.calculateBreakPosition(java.desktop@11.0.13/WrappedPlainView.java:366)
	at javax.swing.text.WrappedPlainView$WrappedLine.breakLines(java.desktop@11.0.13/WrappedPlainView.java:920)
	at javax.swing.text.WrappedPlainView$WrappedLine.getPreferredSpan(java.desktop@11.0.13/WrappedPlainView.java:692)
	at javax.swing.text.BoxView.calculateMajorAxisRequirements(java.desktop@11.0.13/BoxView.java:873)
	at javax.swing.text.BoxView.checkRequests(java.desktop@11.0.13/BoxView.java:931)
	at javax.swing.text.BoxView.setSpanOnAxis(java.desktop@11.0.13/BoxView.java:330)
	at javax.swing.text.BoxView.layout(java.desktop@11.0.13/BoxView.java:710)
	at javax.swing.text.BoxView.setSize(java.desktop@11.0.13/BoxView.java:398)
	at javax.swing.text.WrappedPlainView.setSize(java.desktop@11.0.13/WrappedPlainView.java:519)
	at javax.swing.plaf.basic.BasicTextUI$RootView.setSize(java.desktop@11.0.13/BasicTextUI.java:1818)
	at javax.swing.plaf.basic.BasicTextUI.getPreferredSize(java.desktop@11.0.13/BasicTextUI.java:948)
	at com.github.weisj.darklaf.ui.text.DarkTextUI.getPreferredSize(DarkTextUI.java:223)
	at javax.swing.JComponent.getPreferredSize(java.desktop@11.0.13/JComponent.java:1680)
	at javax.swing.JEditorPane.getPreferredSize(java.desktop@11.0.13/JEditorPane.java:1345)
	at javax.swing.JViewport.getViewSize(java.desktop@11.0.13/JViewport.java:1119)
	at javax.swing.plaf.basic.BasicScrollPaneUI.syncScrollPaneWithViewport(java.desktop@11.0.13/BasicScrollPaneUI.java:330)
	at javax.swing.plaf.basic.BasicScrollPaneUI$Handler.stateChanged(java.desktop@11.0.13/BasicScrollPaneUI.java:1126)
	at javax.swing.JViewport.fireStateChanged(java.desktop@11.0.13/JViewport.java:1490)
	at javax.swing.JViewport.setView(java.desktop@11.0.13/JViewport.java:1089)
	at javax.swing.JScrollPane.setViewportView(java.desktop@11.0.13/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(java.desktop@11.0.13/JTree.java:2967)
	at javax.swing.JTree$TreeSelectionRedirector.valueChanged(java.desktop@11.0.13/JTree.java:3456)
	at javax.swing.tree.DefaultTreeSelectionModel.fireValueChanged(java.desktop@11.0.13/DefaultTreeSelectionModel.java:641)
	at javax.swing.tree.DefaultTreeSelectionModel.notifyPathChange(java.desktop@11.0.13/DefaultTreeSelectionModel.java:1111)
	at javax.swing.tree.DefaultTreeSelectionModel.setSelectionPaths(java.desktop@11.0.13/DefaultTreeSelectionModel.java:297)
	at javax.swing.tree.DefaultTreeSelectionModel.setSelectionPath(java.desktop@11.0.13/DefaultTreeSelectionModel.java:191)
	at javax.swing.JTree.setSelectionPath(java.desktop@11.0.13/JTree.java:1656)

/cc @weisJ

@weisJ

weisJ commented Feb 2, 2022

Copy link
Copy Markdown
Contributor

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

vlsi commented Feb 3, 2022

Copy link
Copy Markdown
Collaborator Author

@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

sginsbourg commented Feb 5, 2022 via email

Copy link
Copy Markdown

@vlsi

vlsi commented Feb 5, 2022

Copy link
Copy Markdown
Collaborator Author

Which setting?

@sginsbourg

sginsbourg commented Feb 5, 2022 via email

Copy link
Copy Markdown

@vlsi

vlsi commented Feb 5, 2022

Copy link
Copy Markdown
Collaborator Author

The idea is to disable kerning for long texts by default

@sginsbourg

sginsbourg commented Feb 5, 2022 via email

Copy link
Copy Markdown

@vlsi

vlsi commented Feb 6, 2022

Copy link
Copy Markdown
Collaborator Author

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

vlsi commented Feb 6, 2022

Copy link
Copy Markdown
Collaborator Author

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

vlsi commented Feb 6, 2022

Copy link
Copy Markdown
Collaborator Author

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
Copy Markdown

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