Производительность выделения памяти Java (SunOS против Windows)

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

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)


person Andrey Adamovich    schedule 28.08.2009    source источник
comment
Похоже, первый компьютер быстрее второго.   -  person MicSim    schedule 28.08.2009
comment
Предположительно, дело в том, что на машине с SunOS тест занимает примерно в 5-6 раз больше времени, чем на машине с Windows.   -  person Avi    schedule 28.08.2009


Ответы (4)


Процессор действительно медленнее на 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());
        }

    }

}
person Andrey Adamovich    schedule 03.09.2009
comment
Последний вывод - опечатка? Должен ли это снова быть SPARC? - person David Moles; 03.09.2009

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

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

person David Moles    schedule 28.08.2009
comment
У вас есть официальные ссылки, которые могут это доказать ;)? - person Andrey Adamovich; 28.08.2009
comment
... нацеленный на презентацию в долларах за Powerpoint. Они потребляют почти столько же энергии, сколько и процессоры Intel. Может быть на 10-20 ватт меньше, но этого недостаточно, чтобы компенсировать потерю производительности. - person ima; 28.08.2009
comment
Подтвердите, что я не знаю о; большая часть того, что я видел, является маркетинговым программным обеспечением. T2 — восьмиядерный чип, не так ли? Вы можете попробовать посмотреть, что происходит с несколькими потоками. Я только что провел быстрый тест на своем настольном компьютере (Core 2 Quad, 2,4 ГГц) всего с 250 строками, и оказалось, что два потока могут выделить по 250 каждый примерно в 1,8 раза быстрее, чем один поток может выделить 250, но для 4 потоков это занимает более чем в 4 раза больше времени. Мне было бы любопытно, как это масштабируется на T2. - person David Moles; 28.08.2009
comment
Я отправил отдельный ответ с описанием многопоточного теста на SPARC. - person Andrey Adamovich; 03.09.2009
comment
T2, на котором мы тестируем, — это 4-ядерный чип, но в производстве он будет 8-ядерным. - person Andrey Adamovich; 03.09.2009

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

person jsight    schedule 28.08.2009
comment
Есть ли способ сделать это быстрее? - person Andrey Adamovich; 28.08.2009
comment
SUN сообщает: Сервер Sun SPARC Enterprise T5120 с технологией Chip Multithreading (CMT) обеспечивает революционный уровень производительности при существенной экономии энергии и места, о чем свидетельствуют результаты ряда мировых рекордов. Не то чтобы я действительно верил в эту маркетинговую чушь, но почему это медленнее? - person Andrey Adamovich; 28.08.2009
comment
@Superfilin: крутить педали сильнее? :-) - person Stephen C; 28.08.2009
comment
Наверное, это то, что мне нужно :) - person Andrey Adamovich; 28.08.2009
comment
Этот чип имеет как минимум 4 ядра, каждое из которых способно выполнять 8 потоков. Возможно, добавление параллелизма является ключом к повышению производительности здесь? Я не думаю, что однопоточная производительность впечатлит. - person jsight; 01.09.2009

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

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

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

(Такие искусственные «микротесты» всегда подвержены подобным эффектам. Я склонен им не доверять.)

person Stephen C    schedule 28.08.2009
comment
Выражение, выводящее время, вычисляется до вызова System.out. Так что это не бутылочное горлышко. - person Andrey Adamovich; 28.08.2009
comment
Ммм ... это не обязательно следует. В любом случае, проведите эксперимент. Если вы правы, умножение количества внутренних циклов на N умножит количество циклов на N. - person Stephen C; 28.08.2009
comment
Умножение внутреннего цикла на 10 не увеличивает число на 10, так как объем потерянной памяти становится все больше и больше с каждой конкатенацией. В основном он выделяет новый char[a.length + аллокация, управляемая.длина] и выбрасывает старый массив. Таким образом, на каждой итерации будет потрачено 17 * i символов. Это составляет как минимум 17/2 * (n ^ 2 - n) потерянного объема памяти. Таким образом, увеличение внутреннего цикла (n) в 10 раз увеличит время в 100 раз. И поверьте мне, System.out здесь не в игре :). - person Andrey Adamovich; 28.08.2009
comment
Тест просто пытается имитировать тяжелое распределение памяти и видит его производительность. Я просто хотел получить объяснение, почему на Sun он намного медленнее. - person Andrey Adamovich; 28.08.2009
comment
ОК, я неправильно прочитал тест (было поздно). Лучшей проверкой моей теории было бы добавить средний цикл, чтобы вы выполнили 1000 конкатенаций N раз в инструментальном цикле. - person Stephen C; 29.08.2009
comment
Этот микротест был создан в ответ на более низкую производительность по сравнению с сервером SPARC и рабочими станциями разработчиков. Таким образом, он показывает, что SPARC работает медленнее в средах с одним или небольшим числом потоков. Смотрите мой ответ на этот вопрос. - person Andrey Adamovich; 03.09.2009
comment
В общем, микро-тесты не отвечают на все вопросы, они, как правило, отвечают на один или два. Вам просто нужно правильно интерпретировать результаты. - person Andrey Adamovich; 03.09.2009