java-topology/test/jdk/performance/client/SwingMark/src/AbstractSwingTest.java
russell@unturf.com 0a580b313d undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
2026-03-26 17:11:57 -04:00

217 lines
7.9 KiB
Java

/*
* Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
import java.awt.ActiveEvent;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.PaintEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
* Derive from this abstract base class when ever
* you want to create a new benchmark test which
* will be run in the SwingMark harness
*.
* The SwingMarkPanel class requires that tests subclass AbstractSwingTest.
*
* @see SwingMarkPanel
*
*/
public abstract class AbstractSwingTest {
public int paintCount = 0;
/**
* Override this when subclassing AbstractSwingTest.
*
* @return A very short description of the test
*/
public abstract String getTestName();
/**
* Override this when subclassing AbstractSwingTest.
* Here you create and initialize the component, or
* group of components, which will be exercised by
* your test.
*
* Typically you will create a JPanel and insert
* components into the panel.
*
* @return The JComponent which will be made visible for your test
*/
public abstract JComponent getTestComponent();
/**
* Override this when subclassing AbstractSwingTest.
* Here you create the code to automate your test,
* This code can be written in many ways. For example, you
* could directly modify the component, or its' model.
* You could also post events to the EventQueue.
* It's up to you
*/
public abstract void runTest();
public int getPaintCount() {
return paintCount;
}
/**
* This static method is used to run your test as a stand-alone
* application. Just pass an instance of your test to this function.
* This is especially useful when you're developing your test, or
* when you want to concentrate on a single area.
*
* To allow your test to be run stand-alone, you need to add a main() that
* looks like this
*
* public static void main(String[] args) {
* runStandAloneTest( new MyTestName() );
* }
*/
@SuppressWarnings("deprecation")
public static void runStandAloneTest(AbstractSwingTest test) {
long startTime = System.currentTimeMillis();
JFrame f = new JFrame();
f.addWindowListener( new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);}} );
f.getContentPane().add( test.getTestComponent() );
f.pack();
f.show();
rest();
syncRam();
long endStartup = System.currentTimeMillis();
test.runTest();
rest();
long endTests = System.currentTimeMillis();
System.out.println("Startup Time: " + (endStartup - startTime));
System.out.println("Test Time: " + (endTests - endStartup));
if (test.getPaintCount() > 0) {
System.out.println("Called Paint: " + test.getPaintCount() + " times");
} else {
System.out.println("Painting calls not counted.");
}
}
@SuppressWarnings("removal")
public static void syncRam() {
System.gc();
System.runFinalization();
System.gc();
try {
Thread.sleep(100);
} catch (Exception e) {
System.out.println( "failed sleeping " + e);
}
}
private static Component BOGUS_COMPONENT = new JPanel();
private static EventQueue Q = Toolkit.getDefaultToolkit().getSystemEventQueue();
// Invoked during tests to wait until the current event has finished
// processing. At the time of this writing AWT's EventQueue has 3
// queues: LOW, NORMAL and HIGH. Swing's repaint events end up on
// the NORMAL queue, AWT's paint events end up on the LOW queue. Runnable
// events end up on the NORMAL queue. The code to rest blocks until ALL
// queues are empty. This is accomplished by adding an event
// (NotifyingPaintEvent) to the EventQueue. When the event is dispatched
// the EventQueue is checked, if the EQ is empty rest exits, otherwise
// rest loops through adding another event to the EQ.
public static void rest() {
Thread.yield();
boolean qEmpty = false;
while (!qEmpty) {
NotifyingPaintEvent e = new NotifyingPaintEvent(BOGUS_COMPONENT);
Q.postEvent(e);
synchronized(e) {
// Wait until the event has been dispatched
while (!e.isDispatched()) {
try {
e.wait();
} catch (InterruptedException ie) {
System.out.println("IE: " + ie);
}
}
// Check if the q is empty
qEmpty = e.qEmpty();
}
}
Toolkit.getDefaultToolkit().sync();
}
private static class NotifyingPaintEvent extends PaintEvent
implements ActiveEvent {
private static int nextLocation;
boolean dispatched = false;
boolean qEmpty;
private int location;
NotifyingPaintEvent(Component x) {
super(x, PaintEvent.UPDATE, null);
synchronized(NotifyingPaintEvent.class) {
location = nextLocation++;
}
}
// 1.3 uses this for coalescing. To avoid having these events
// coalesce return a new location for each event.
public Rectangle getUpdateRect() {
return new Rectangle(location, location, 1, 1);
}
public synchronized boolean isDispatched() {
return dispatched;
}
public synchronized boolean qEmpty() {
return qEmpty;
}
public void dispatch() {
qEmpty = (Q.peekEvent() == null);
synchronized(this) {
dispatched = true;
notifyAll();
}
}
}
}