<Swing Dev> Extension method for AbstractDocument.Content?

Paulo Levi i30817 at gmail.com
Wed Jul 11 13:55:49 UTC 2012


Tried to do a performance and memory test; they fail or pass depending on
the order the Documents are tested.
Could someone more experienced tell me what am i doing wrong? The
performance test i expected to fail (since reflection is much slower than
override), but the memory test i did not expect to depend on order.

import java.io.BufferedReader;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import javax.swing.event.DocumentEvent;
import javax.swing.event.UndoableEditEvent;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.DefaultStyledDocument.ElementSpec;
import javax.swing.text.GapContent;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class DocumentTest {

    public DocumentTest() {
    }

    @BeforeClass
    public static void setUpClass() throws Exception {
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
    }

    @Before
    public void setUp() {
    }

    @After
    public void tearDown() {
    }
    OldTestDocument oldDoc = new OldTestDocument();
    NewTestDocument newDoc = new NewTestDocument();

    /**
     * Test of insert method performance and memory
     */
    @Test
    public void testInsert() throws Exception {
        System.out.println("insert");
        List<ElementSpec> l = new ArrayList<>();

        try (BufferedReader r = Files.newBufferedReader(Paths.get("War and
Peace.txt"), Charset.forName("us-ascii"))) {
            while (r.ready()) {
                String line = r.readLine();
                l.add(new ElementSpec(null, ElementSpec.StartTagType));
                l.add(new ElementSpec(null, ElementSpec.ContentType,
line.toCharArray(), 0, line.length()));
                l.add(new ElementSpec(null, ElementSpec.EndTagType));
            }
        }
        //every styled document must end with a 'implied newline'
        l.add(new ElementSpec(null, ElementSpec.ContentType, new
char[]{'\n'}, 0, 1));

        ElementSpec[] arr = (ElementSpec[]) l.toArray(new ElementSpec[0]);
        long time, mem, elapsedTime1, elapsedTime2, memory1, memory2;
        ThreadMXBean t = ManagementFactory.getThreadMXBean();
        MemoryMXBean m = ManagementFactory.getMemoryMXBean();

        //using non-heap memory because we are testing the memory impact of
the stringbuilder
        //inside DefaultStyledDocument.insert(int offset, ElementSpec[]
data)
        //to switch the order exchange the next 6 lines of code with the
other six lines below

        m.gc();
        mem = m.getNonHeapMemoryUsage().getUsed();
        time = t.getCurrentThreadCpuTime();
        oldDoc.insert(0, arr);
        elapsedTime2 = t.getCurrentThreadCpuTime() - time;
        memory2 = m.getNonHeapMemoryUsage().getUsed() - mem;

        m.gc();
        mem = m.getNonHeapMemoryUsage().getUsed();
        time = t.getCurrentThreadCpuTime();
        newDoc.insert(0, arr);
        elapsedTime1 = t.getCurrentThreadCpuTime() - time;
        memory1 = m.getNonHeapMemoryUsage().getUsed() - mem;


        System.out.println("new style insert time : " + elapsedTime1 + "
memory used : " + memory1);
        System.out.println("old style insert time : " + elapsedTime2 + "
memory used : " + memory2);

        assert memory1 < memory2 : "old style insert took less memory than
new style insert!";
        assert elapsedTime1 < elapsedTime2 : "old style insert took less
time than new style insert!";
    }

    class OldTestDocument extends DefaultStyledDocument {

        @Override
        public void insert(int offset, ElementSpec[] data) throws
BadLocationException {
            super.insert(offset, data);
        }
    }

    final class NewTestDocument extends DefaultStyledDocument {

        private final Method replace;
        private final Object[] bulkArgs = new Object[4];

        public NewTestDocument() {
            super();
            try {
                Class[] args = new Class[]{Integer.TYPE, Integer.TYPE,
Object.class, Integer.TYPE};
                replace =
GapContent.class.getSuperclass().getDeclaredMethod("replace", args);
                replace.setAccessible(true);
            } catch (Exception ex) {
                throw new AssertionError(ex);
            }
        }

        @Override
        public void insert(int offset, ElementSpec[] data) throws
BadLocationException {
            if (offset > getLength() || offset < 0) {
                throw new BadLocationException("Invalid insert", offset);
            }
            if (data == null || data.length == 0) {
                return;
            }

            writeLock();
            try {
                Content content = getContent();
                //since instead of doing normal string insert we are going
to use the gapvector directly, we don't do this
                //UndoableEdit cEdit = content.insertString(offset,
sb.toString());
                int charArraysSize = 0;
                int index = offset;
                for (ElementSpec e : data) {
                    if (e.getLength() > 0) {
                        charArraysSize += e.getLength();
                        bulkArgs[0] = index;
                        bulkArgs[1] = e.getOffset();
                        bulkArgs[2] = e.getArray();
                        bulkArgs[3] = e.getLength();
                        index += e.getLength();
                        try {
                            replace.invoke(content, bulkArgs);
                        } catch (Exception ex) {
                            throw new AssertionError(ex);
                        }
                    }
                }
                if (charArraysSize == 0) {
                    return;
                }
                //created the undoable edit corresponding to the whole
inserted string
                //this can't be created since it is package default in
GapContent
                //UndoableEdit cEdit = new InsertUndo(offset,
charArraysSize);
                DefaultDocumentEvent evnt = new
DefaultDocumentEvent(offset, charArraysSize,
DocumentEvent.EventType.INSERT);
                //evnt.addEdit(cEdit);
                buffer.insert(offset, charArraysSize, data, evnt);
                // update bidi (possibly)
                super.insertUpdate(evnt, null);
                // notify the listeners
                evnt.end();
                fireInsertUpdate(evnt);
                fireUndoableEditUpdate(new UndoableEditEvent(this, evnt));
            } finally {
                writeUnlock();
            }
        }
    }
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/swing-dev/attachments/20120711/2c6ec606/attachment.html>


More information about the swing-dev mailing list