Производительность выделения памяти Java (SunOS против Windows) - PullRequest
0 голосов
/ 28 августа 2009

У меня очень простой модульный тест, который просто выделяет много строк:

public class AllocationSpeedTest extends TestCase {

    public void testAllocation() throws Exception {

        for (int i = 0; i < 1000; i++) {
            long startTime = System.currentTimeMillis();
            String a = "dummy";
            for (int j = 0; j < 1000; j++) {
                a += "allocation driven";
            }
            System.out.println(i + ": " + (System.currentTimeMillis() - startTime) + "ms " + a.length());
        }

    }

}

На моем ПК с Windows (Intel Core Duo, 2,2 ГГц, 2 ГБ) в среднем печатается:

...
71: 47ms 17005
72: 47ms 17005
73: 46ms 17005
74: 47ms 17005
75: 47ms 17005
76: 47ms 17005
77: 47ms 17005
78: 47ms 17005
79: 47ms 17005
80: 62ms 17005
81: 47ms 17005
...

В SunOS (5.10 Generic_138888-03 sun4v sparc SUNW, SPARC-Enterprise-T5120):

...
786: 227ms 17005
787: 294ms 17005
788: 300ms 17005
789: 224ms 17005
790: 260ms 17005
791: 242ms 17005
792: 263ms 17005
793: 287ms 17005
794: 219ms 17005
795: 279ms 17005
796: 278ms 17005
797: 231ms 17005
798: 291ms 17005
799: 246ms 17005
800: 327ms 17005
...

Версия JDK 1.4.2_18 на обеих машинах. Параметры JVM одинаковы:

–server –Xmx256m –Xms256m

Может кто-нибудь объяснить, почему супер-сервер SUN работает медленнее?

(http://www.sun.com/servers/coolthreads/t5120/performance.xml)

Ответы [ 4 ]

2 голосов
/ 03 сентября 2009

Процессор действительно медленнее в SPARC (1,2 ГГц) и, как сказал один из инженеров Sun, T2 обычно в 3 раза медленнее для однопоточных приложений, чем современные процессоры Intel. Однако он также заявил, что в многопоточной среде SPARC должен работать быстрее.

Я провел многопоточный тест с использованием библиотеки GroboUtils и проверил как распределения (через конкатенации), так и простые вычисления (a + = j * j) для тестирования процессора. И я получил следующие результаты:

1 thread : Intel : Calculations test : 43ms
100 threads : Intel : Calculations test : 225ms

1 thread : Intel : Allocations test : 35ms
100 threads : Intel : Allocations test : 1754ms

1 thread : SPARC : Calculations test : 197ms
100 threads : SPARC : Calculations test : 261ms

1 thread : SPARC : Allocations test : 236ms
100 threads : SPARC : Allocations test : 1517ms

SPARC демонстрирует свою мощь, опережая Intel на 100 потоков.

Здесь идет тест многопоточного расчета:

import java.util.ArrayList;
import java.util.List;

import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner;
import net.sourceforge.groboutils.junit.v1.TestRunnable;
import junit.framework.TestCase;

public class TM1_CalculationSpeedTest extends TestCase {

    public void testCalculation() throws Throwable {

        List threads = new ArrayList();
        for (int i = 0; i < 100; i++) {
            threads.add(new Requester());
        }
        MultiThreadedTestRunner mttr = new MultiThreadedTestRunner((TestRunnable[]) threads.toArray(new TestRunnable[threads.size()]));
        mttr.runTestRunnables(2 * 60 * 1000);

    }

    public class Requester extends TestRunnable {

        public void runTest() throws Exception {
            long startTime = System.currentTimeMillis();
            long a = 0;
            for (int j = 0; j < 10000000; j++) {
                a += j * j;
            }
            long endTime = System.currentTimeMillis();
            System.out.println(this + ": " + (endTime - startTime) + "ms " + a);
        }

    }

}

Здесь идет тест многопоточного размещения:

import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;
import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner;
import net.sourceforge.groboutils.junit.v1.TestRunnable;

public class TM2_AllocationSpeedTest extends TestCase {

    public void testAllocation() throws Throwable {

        List threads = new ArrayList();
        for (int i = 0; i < 100; i++) {
            threads.add(new Requester());   
        }
        MultiThreadedTestRunner mttr = new MultiThreadedTestRunner((TestRunnable[]) threads.toArray(new TestRunnable[threads.size()]));
        mttr.runTestRunnables(2 * 60 * 1000);

    }

    public class Requester extends TestRunnable {

        public void runTest() throws Exception {
            long startTime = System.currentTimeMillis();
            String a = "dummy";
            for (int j = 0; j < 1000; j++) {
                a += "allocation driven";
            }
            long endTime = System.currentTimeMillis();
            System.out.println(this + ": " + (endTime - startTime) + "ms " + a.length());
        }

    }

}
1 голос
/ 28 августа 2009

Насколько я понимаю, машины на базе UltraSPARC T2 нацелены на производительность, а не на производительность. Вы можете попытаться разделить время распределения на энергопотребление и посмотреть, какие числа вы получаете. :)

Есть ли причина, по которой вы используете 1.4.2 вместо 1.6?

0 голосов
/ 28 августа 2009

Не думаю, что это измерение распределения памяти. Для начала, в a += "allocation driven"; происходит огромное количество копий символов. Но я подозреваю, что реальным узким местом является получение выходных данных с System.out.println(...) через сетевые уровни из приложения на сервере Sun на удаленную рабочую станцию.

В качестве эксперимента попробуйте умножить количество внутренних циклов на 10 и 100 и посмотрите, не ускоряет ли это сервер Sun относительно вашей рабочей станции.

Еще одна вещь, которую вы можете попробовать - это переместить внутренний цикл в отдельную процедуру. Вполне возможно, что, поскольку вы выполняете всю работу за один вызов main, JIT-компилятор никогда не получает возможности скомпилировать ее.

(Подобные искусственные "микро-тесты" всегда подвержены подобным эффектам. Я склонен их не доверять.)

0 голосов
/ 28 августа 2009

Аппаратное обеспечение SunOS работает медленнее, а виртуальная машина также может быть несколько медленнее.

...