Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/Java/Tomcat/test/org/apache/catalina/valves/   (Apache Software Stiftung Version 2.4.65©)  Datei vom 10.10.2023 mit Größe 17 kB image not shown  

Quelle  Benchmarks.java   Sprache: JAVA

 
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.catalina.valves;

import java.text.SimpleDateFormat;
import java.util.Date;

import org.junit.Test;

/**
 * Some simple micro-benchmarks to help determine best approach for thread safety in valves, particularly the
 * {@link AccessLogValve}. Implemented as JUnit tests to make the simple to execute but does not used Test* as the class
 * name to avoid being included in the automated unit tests.
 */

public class Benchmarks {
    @Test
    public void testAccessLogGetDate() throws Exception {
        // Is it better to use a sync or a thread local here?
        BenchmarkTest benchmark = new BenchmarkTest();
        Runnable[] tests = new Runnable[] { new GetDateBenchmarkTest_Sync(), new GetDateBenchmarkTest_Local(),
                new GetDateBenchmarkTest_LocalMutableLong(), new GetDateBenchmarkTest_LocalStruct() };
        benchmark.doTest(5, tests);
    }

    private static class GetDateBenchmarkTest_Sync implements Runnable {

        @Override
        public String toString() {
            return "Syncs";
        }

        private volatile long currentMillis = 0;
        private volatile Date currentDate = null;

        @Override
        public void run() {
            getCurrentDate();
        }

        public Date getCurrentDate() {
            long systime = System.currentTimeMillis();
            if ((systime - currentMillis) > 1000) {
                synchronized (this) {
                    if ((systime - currentMillis) > 1000) {
                        currentDate = new Date(systime);
                        currentMillis = systime;
                    }
                }
            }
            return currentDate;
        }
    }

    private static class GetDateBenchmarkTest_Local implements Runnable {

        @Override
        public String toString() {
            return "ThreadLocals";
        }

        private ThreadLocal<Long> currentMillisLocal = new ThreadLocal<>() {
            @Override
            protected Long initialValue() {
                return Long.valueOf(0);
            }
        };

        private ThreadLocal<Date> currentDateLocal = new ThreadLocal<>();

        @Override
        public void run() {
            getCurrentDate();
        }

        public Date getCurrentDate() {
            long systime = System.currentTimeMillis();
            if ((systime - currentMillisLocal.get().longValue()) > 1000) {
                currentDateLocal.set(new Date(systime));
                currentMillisLocal.set(Long.valueOf(systime));
            }
            return currentDateLocal.get();
        }
    }

    private static class GetDateBenchmarkTest_LocalMutableLong implements Runnable {

        @Override
        public String toString() {
            return "ThreadLocals with a mutable Long";
        }

        private static class MutableLong {
            long value = 0;
        }

        private ThreadLocal<MutableLong> currentMillisLocal = new ThreadLocal<>() {
            @Override
            protected MutableLong initialValue() {
                return new MutableLong();
            }
        };

        private ThreadLocal<Date> currentDateLocal = new ThreadLocal<>();

        @Override
        public void run() {
            getCurrentDate();
        }

        public Date getCurrentDate() {
            long systime = System.currentTimeMillis();
            if ((systime - currentMillisLocal.get().value) > 1000) {
                currentDateLocal.set(new Date(systime));
                currentMillisLocal.get().value = systime;
            }
            return currentDateLocal.get();
        }
    }

    private static class GetDateBenchmarkTest_LocalStruct implements Runnable {

        @Override
        public String toString() {
            return "single ThreadLocal";
        }

        // note, that we can avoid (long -> Long) conversion
        private static class Struct {
            public long currentMillis = 0;
            public Date currentDate;
        }

        private ThreadLocal<Struct> currentStruct = new ThreadLocal<>() {
            @Override
            protected Struct initialValue() {
                return new Struct();
            }
        };

        @Override
        public void run() {
            getCurrentDate();
        }

        public Date getCurrentDate() {
            Struct struct = currentStruct.get();
            long systime = System.currentTimeMillis();
            if ((systime - struct.currentMillis) > 1000) {
                struct.currentDate = new Date(systime);
                struct.currentMillis = systime;
            }
            return struct.currentDate;
        }
    }

    @Test
    public void testAccessLogTimeDateElement() throws Exception {
        // Is it better to use a sync or a thread local here?
        BenchmarkTest benchmark = new BenchmarkTest();
        Runnable[] tests = new Runnable[] { new TimeDateElementBenchmarkTest_Sync(),
                new TimeDateElementBenchmarkTest_Local(), new TimeDateElementBenchmarkTest_LocalStruct(),
                new TimeDateElementBenchmarkTest_LocalStruct_SBuilder() };
        benchmark.doTest(5, tests);
    }

    private abstract static class TimeDateElementBenchmarkTestBase {
        protected static final String months[] = { "Jan""Feb""Mar""Apr""May""Jun""Jul""Aug""Sep""Oct",
                "Nov""Dec" };

        protected String lookup(String month) {
            int index;
            try {
                index = Integer.parseInt(month) - 1;
            } catch (Throwable t) {
                index = 0; // cannot happen, in theory
            }
            return months[index];
        }
    }

    private static class TimeDateElementBenchmarkTest_Sync extends TimeDateElementBenchmarkTestBase
            implements Runnable {

        @Override
        public String toString() {
            return "Syncs";
        }

        private volatile Date currentDate = new Date();
        private volatile String currentDateString = null;
        private SimpleDateFormat dayFormatter = new SimpleDateFormat("dd");
        private SimpleDateFormat monthFormatter = new SimpleDateFormat("MM");
        private SimpleDateFormat yearFormatter = new SimpleDateFormat("yyyy");
        private SimpleDateFormat timeFormatter = new SimpleDateFormat("hh:mm:ss");

        @Override
        public void run() {
            printDate();
        }

        public String printDate() {
            StringBuilder buf = new StringBuilder();
            Date date = getDateSync();
            if (currentDate != date) {
                synchronized (this) {
                    if (currentDate != date) {
                        StringBuilder current = new StringBuilder(32);
                        current.append('[');
                        current.append(dayFormatter.format(date)); // Day
                        current.append('/');
                        current.append(lookup(monthFormatter.format(date))); // Month
                        current.append('/');
                        current.append(yearFormatter.format(date)); // Year
                        current.append(':');
                        current.append(timeFormatter.format(date)); // Time
                        current.append(']');
                        currentDateString = current.toString();
                        currentDate = date;
                    }
                }
            }
            buf.append(currentDateString);
            return buf.toString();
        }

        private Date getDateSync() {
            long systime = System.currentTimeMillis();
            if ((systime - currentDate.getTime()) > 1000) {
                synchronized (this) {
                    if ((systime - currentDate.getTime()) > 1000) {
                        currentDate.setTime(systime);
                    }
                }
            }
            return currentDate;
        }
    }

    private static class TimeDateElementBenchmarkTest_Local extends TimeDateElementBenchmarkTestBase
            implements Runnable {

        @Override
        public String toString() {
            return "ThreadLocals";
        }

        private ThreadLocal<String> currentDateStringLocal = new ThreadLocal<>();

        private ThreadLocal<Date> currentDateLocal = new ThreadLocal<>() {
            @Override
            protected Date initialValue() {
                return new Date();
            }
        };
        private ThreadLocal<SimpleDateFormat> dayFormatterLocal = new ThreadLocal<>() {
            @Override
            protected SimpleDateFormat initialValue() {
                return new SimpleDateFormat("dd");
            }
        };
        private ThreadLocal<SimpleDateFormat> monthFormatterLocal = new ThreadLocal<>() {
            @Override
            protected SimpleDateFormat initialValue() {
                return new SimpleDateFormat("MM");
            }
        };
        private ThreadLocal<SimpleDateFormat> yearFormatterLocal = new ThreadLocal<>() {
            @Override
            protected SimpleDateFormat initialValue() {
                return new SimpleDateFormat("yyyy");
            }
        };
        private ThreadLocal<SimpleDateFormat> timeFormatterLocal = new ThreadLocal<>() {
            @Override
            protected SimpleDateFormat initialValue() {
                return new SimpleDateFormat("hh:mm:ss");
            }
        };

        @Override
        public void run() {
            printDate();
        }

        public String printDate() {
            getDateLocal();
            if (currentDateStringLocal.get() == null) {
                StringBuilder current = new StringBuilder(32);
                current.append('[');
                current.append(dayFormatterLocal.get().format(currentDateLocal.get())); // Day
                current.append('/');
                current.append(lookup(monthFormatterLocal.get().format(currentDateLocal.get())))// Month
                current.append('/');
                current.append(yearFormatterLocal.get().format(currentDateLocal.get())); // Year
                current.append(':');
                current.append(timeFormatterLocal.get().format(currentDateLocal.get())); // Time
                current.append(']');
                currentDateStringLocal.set(current.toString());
            }
            return currentDateStringLocal.get();
        }

        private Date getDateLocal() {
            long systime = System.currentTimeMillis();
            if ((systime - currentDateLocal.get().getTime()) > 1000) {
                currentDateLocal.get().setTime(systime);
                currentDateStringLocal.set(null);
            }
            return currentDateLocal.get();
        }
    }

    private static class TimeDateElementBenchmarkTest_LocalStruct extends TimeDateElementBenchmarkTestBase
            implements Runnable {

        @Override
        public String toString() {
            return "single ThreadLocal";
        }

        private static class Struct {
            public String currentDateString;
            public Date currentDate = new Date();
            public SimpleDateFormat dayFormatter = new SimpleDateFormat("dd");
            public SimpleDateFormat monthFormatter = new SimpleDateFormat("MM");
            public SimpleDateFormat yearFormatter = new SimpleDateFormat("yyyy");
            public SimpleDateFormat timeFormatter = new SimpleDateFormat("hh:mm:ss");
        }

        private ThreadLocal<Struct> structLocal = new ThreadLocal<>() {
            @Override
            protected Struct initialValue() {
                return new Struct();
            }
        };

        @Override
        public void run() {
            printDate();
        }

        public String printDate() {
            getDateLocal();
            Struct struct = structLocal.get();
            if (struct.currentDateString == null) {
                StringBuilder current = new StringBuilder(32);
                current.append('[');
                current.append(struct.dayFormatter.format(struct.currentDate)); // Day
                current.append('/');
                current.append(lookup(struct.monthFormatter.format(struct.currentDate))); // Month
                current.append('/');
                current.append(struct.yearFormatter.format(struct.currentDate)); // Year
                current.append(':');
                current.append(struct.timeFormatter.format(struct.currentDate)); // Time
                current.append(']');
                struct.currentDateString = current.toString();
            }
            return struct.currentDateString;
        }

        private Date getDateLocal() {
            Struct struct = structLocal.get();
            long systime = System.currentTimeMillis();
            if ((systime - struct.currentDate.getTime()) > 1000) {
                struct.currentDate.setTime(systime);
                struct.currentDateString = null;
            }
            return struct.currentDate;
        }
    }

    private static class TimeDateElementBenchmarkTest_LocalStruct_SBuilder extends TimeDateElementBenchmarkTestBase
            implements Runnable {

        @Override
        public String toString() {
            return "single ThreadLocal, with StringBuilder";
        }

        private static class Struct {
            public String currentDateString;
            public Date currentDate = new Date();
            public SimpleDateFormat dayFormatter = new SimpleDateFormat("dd");
            public SimpleDateFormat monthFormatter = new SimpleDateFormat("MM");
            public SimpleDateFormat yearFormatter = new SimpleDateFormat("yyyy");
            public SimpleDateFormat timeFormatter = new SimpleDateFormat("hh:mm:ss");
        }

        private ThreadLocal<Struct> structLocal = new ThreadLocal<>() {
            @Override
            protected Struct initialValue() {
                return new Struct();
            }
        };

        @Override
        public void run() {
            printDate();
        }

        public String printDate() {
            getDateLocal();
            Struct struct = structLocal.get();
            if (struct.currentDateString == null) {
                StringBuilder current = new StringBuilder(32);
                current.append('[');
                current.append(struct.dayFormatter.format(struct.currentDate)); // Day
                current.append('/');
                current.append(lookup(struct.monthFormatter.format(struct.currentDate))); // Month
                current.append('/');
                current.append(struct.yearFormatter.format(struct.currentDate)); // Year
                current.append(':');
                current.append(struct.timeFormatter.format(struct.currentDate)); // Time
                current.append(']');
                struct.currentDateString = current.toString();
            }
            return struct.currentDateString;
        }

        private Date getDateLocal() {
            Struct struct = structLocal.get();
            long systime = System.currentTimeMillis();
            if ((systime - struct.currentDate.getTime()) > 1000) {
                struct.currentDate.setTime(systime);
                struct.currentDateString = null;
            }
            return struct.currentDate;
        }
    }

    private static class BenchmarkTest {
        public void doTest(int threadCount, Runnable[] tests) throws Exception {
            for (int iterations = 1000000; iterations < 10000001; iterations += 1000000) {
                for (Runnable test : tests) {
                    doTestInternal(threadCount, iterations, test);
                }
            }
        }

        private void doTestInternal(int threadCount, int iterations, Runnable test) throws Exception {
            long start = System.currentTimeMillis();
            Thread[] threads = new Thread[threadCount];
            for (int i = 0; i < threadCount; i++) {
                threads[i] = new Thread(new TestThread(iterations, test));
            }
            for (int i = 0; i < threadCount; i++) {
                threads[i].start();
            }
            for (int i = 0; i < threadCount; i++) {
                threads[i].join();
            }
            long end = System.currentTimeMillis();

            System.out.println(test.getClass().getSimpleName() + ": " + threadCount + " threads and " + iterations +
                    " iterations using " + test + " took " + (end - start) + "ms");
        }
    }

    private static class TestThread implements Runnable {
        private int count;
        private Runnable test;

        TestThread(int count, Runnable test) {
            this.count = count;
            this.test = test;
        }

        @Override
        public void run() {
            for (int i = 0; i < count; i++) {
                test.run();
            }
        }
    }
}

Messung V0.5
C=94 H=91 G=92

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.