Время умножения в BigInteger

Мой мини тест:

import java.math.*;
import java.util.*;
import java.io.*;
public class c
{
    static Random rnd = new Random();
    public static String addDigits(String a, int n)
    {
        if(a==null) return null;
        if(n<=0) return a;
        for(int i=0; i<n; i++)
            a+=rnd.nextInt(10);
        return a;
    }
    public static void main(String[] args) throws IOException
    {
        int n = 10000; \\number of iterations
        int k = 10;    \\number of digits added at each iteration

        BigInteger a;
        BigInteger b;

        String as = "";
        String bs = "";
        as += rnd.nextInt(9)+1;
        bs += rnd.nextInt(9)+1;
        a = new BigInteger(as);
        b = new BigInteger(bs);
        FileWriter fw = new FileWriter("c.txt");
        long t1 = System.nanoTime();
        a.multiply(b);
        long t2 = System.nanoTime();
        //fw.write("1,"+(t2-t1)+"\n");
        if(k>0) {
            as = addDigits(as, k-1);
            bs = addDigits(as, k-1);
        }
        for(int i=0; i<n; i++)
        {
            a = new BigInteger(as);
            b = new BigInteger(bs);
            t1 = System.nanoTime();
            a.multiply(b);
            t2 = System.nanoTime();
            fw.write(((i+1)*k)+","+(t2-t1)+"\n");
            if(i < n-1)
            {
                as = addDigits(as, k);
                bs = addDigits(as, k);
            }
            System.out.println((i+1)*k);
        }       

        fw.close();
    }
}

Он измеряет время умножения n-значного BigInteger

Результат: введите описание изображения здесь

Вы можете легко увидеть тенденцию, но почему так много шума выше 50000 цифр? Это из-за сборщика мусора или что-то еще влияет на мои результаты? При выполнении теста другие приложения не работали.

Результат теста с нечетными цифрами. Тест был короче (n = 1000, k = 100)

введите описание изображения здесь

Нечетные цифры (n = 10000, k = 10) введите описание изображения здесь

Как видите, между 65000 и 70000 очень большой шум. Интересно, почему ...

Нечетные цифры (n = 10000, k = 10), System.gc() каждые 1000 итераций введите описание изображения здесьРезультаты шум между 50000-70000


person Jan Ajan    schedule 24.05.2012    source источник
comment
Невозможно узнать информацию, которую вы показали. Почему бы вам не попробовать `System.gc ()` каждые 500-1000 итераций, чтобы увидеть, сгладит ли это ситуацию.   -  person hvgotcodes    schedule 24.05.2012
comment
Никаких других запущенных приложений не было. Вы работаете в вычислительной среде реального времени без операционной системы с разделением времени (например, Windows)? Невозможно гарантировать, что каждый цикл ЦП выделяется только вашему приложению.   -  person mellamokb    schedule 24.05.2012
comment
Извините, что не по теме, но какую программу вы планируете использовать?   -  person keyser    schedule 24.05.2012
comment
Никаких других запущенных приложений не было. equals Никаких других приложений, кроме операционной системы (и системных служб и т. д.), не было.   -  person Jan Ajan    schedule 24.05.2012
comment
@Keyser, я использую Graph из padowan.dk   -  person Jan Ajan    schedule 24.05.2012
comment
@ ulu5 вы используете en.wikipedia.org/wiki/Karatsuba_algorithm?   -  person Jan Ajan    schedule 24.05.2012
comment
@ ulu5 ваша ссылка, в соответствии с исходным кодом, говорит, что JDK не изменяет алгоритмы.   -  person Affe    schedule 25.05.2012
comment
Кстати, эта ссылка вызывает O (нм) экспоненциальный ??   -  person Marko Topolnik    schedule 25.05.2012
comment
Java (TM) SE Runtime Environment (сборка 1.7.0_02-b13) 64-разрядная серверная виртуальная машина Java HotSpot (TM) (сборка 22.0-b10, смешанный режим)   -  person Jan Ajan    schedule 25.05.2012
comment
@ ulu5, я попробую ввести только нечетные цифры в BigInteger, но полная проверка займет некоторое время. Результаты выложу позже.   -  person Jan Ajan    schedule 25.05.2012
comment
Это gc, эффект замедления, вероятно, является следствием разогрева jvm. Время от времени вызывайте System.gc () вне временного блока для подтверждения.   -  person esej    schedule 25.05.2012
comment
@hvgotcodes @esej Из документации System.gc () Вызов метода gc предполагает, что виртуальная машина Java затрачивает усилия на переработку неиспользуемых объектов [...]. Другими словами, System.gc() - всего лишь намек для JVM, нет способа узнать, когда и как на самом деле выполняется сборщик мусора.   -  person matsev    schedule 25.05.2012
comment
@matsev Спорить не буду, но есть способы узнать. В противном случае правильно. Вполне возможно, что такой тест даст ответ на этот вопрос.   -  person esej    schedule 25.05.2012
comment
@matsev Вы можете просто проверить это с помощью VisualVM.   -  person Andrew    schedule 25.05.2012
comment
@matsev Документ gc в основном говорит, что я, вероятно, сделаю gc, только не верьте мне на слово, он не говорит, что вы просто называете меня, как хотите, я буду рад вас игнорировать :) Когда Я поигрался с ним, запустив gc () дважды подряд, надежно изменил размер кучи только до живых объектов - и это все, что нужно, чтобы результаты теста были правильными.   -  person Marko Topolnik    schedule 25.05.2012
comment
@Andrew Что ж, вы можете проверить результат того, что произошло, с помощью VisualVM. Однако, когда вы пишете свой код, вы не можете предсказать, будет ли GC выполняться до выполнения следующего оператора, когда объект потерял свою последнюю ссылку или когда JVM завершит работу.   -  person matsev    schedule 25.05.2012
comment
@esej Я думаю, по способам узнать, что ты имеешь в виду, что случилось? Я согласен с тем, что вы можете отслеживать, что произошло (например, используя VisualVM), и этого может быть достаточно для решения проблемы.   -  person matsev    schedule 25.05.2012
comment
@Marko Мне нравится ваша цитата. Я, вероятно, сделаю gc, только не верьте мне на слово, это было в основном ключевым посланием в моем первоначальном комментарии. Хорошо, что вы нашли решение своей проблемы, однако оно может вести себя так же, а может и не вести себя, если вы используете JVM, разработанную другим поставщиком. Фактически, разные JVM от одного и того же поставщика могут вести себя по-разному, например Oracle изменила реализацию GC в недавнем обновлении 4 JDK 7. выпуск.   -  person matsev    schedule 25.05.2012
comment
Помните, что с помощью класса GarbageCollectorMXBean вы можете получить информацию о том, происходил ли сборщик мусора. Это не обязательно должно быть загадкой.   -  person Neil Coffey    schedule 25.05.2012
comment
Очевидно, вы должны усреднить несколько измерений для каждой точки данных при проведении такого теста - я не могу точно сказать по вашему коду и последующей предварительной обработке, делаете ли вы это.   -  person Neil Coffey    schedule 25.05.2012
comment
Я бы предположил, что этот конкретный диапазон чисел совпадает с каким-то определенным пороговым значением GC - возможно, генерирует определенное количество мусора, которое запускает вещи GCish?   -  person Louis Wasserman    schedule 25.05.2012
comment
@MarkoTopolnik - Когда я играл с ним, запуск gc () дважды подряд надежно изменял размер кучи только для живых объектов. Проблема в том, что ваш опыт НЕ МОЖЕТ быть обобщен на другие JVM или даже на ту же JVM с разными параметрами GC.   -  person Stephen C    schedule 25.05.2012
comment
@StephenC Это не проблема, но предостережение. OP может убедить себя для своей конкретной настройки, что работает, а когда это действительно работает, ну что ж, тогда все. Я привел пример того, как это сработало у меня.   -  person Marko Topolnik    schedule 25.05.2012
comment
@matsev Но вы тестируете одну конкретную установку. В конце концов, получаемые вами результаты так же специфичны для этой настройки, как и поведение gc. Другое дело, как убедить себя, что gc () делает gc. Я повторил ту же процедуру выделения памяти, за которой следовали два gc, а затем Runtime.freeMemory, много раз, и каждый раз результаты были одинаковыми. Однако без этой проверки вы ничего не можете знать заранее.   -  person Marko Topolnik    schedule 25.05.2012


Ответы (2)


Я также подозреваю, что это эффект разогрева JVM. Не разогрев, связанный с загрузкой классов или JIT-компилятором, а разогрев кучи.

Поместите цикл (java) вокруг всего теста и запустите его несколько раз. (Если это даст вам те же графики, что и раньше ... у вас будет свидетельство, что это не эффект разминки. В настоящее время у вас нет каких-либо эмпирических свидетельств того или иного рода.)


Другая возможность заключается в том, что шум вызван взаимодействием вашего теста с ОС и / или другими устройствами, работающими на машине.

  • Вы записываете свои временные данные в небуферизованный поток. Это означает МНОГО системных вызовов и (потенциально) множество мелкозернистых операций записи на диск.
  • Вы делаете МНОГО обращений к nanoTime(), и это может создать шум.
  • Если на вашем компьютере работает что-то еще (например, вы просматриваете веб-страницы), это немного замедлит ваш тест и вызовет шум.
  • Может возникнуть конкуренция за физическую память ... если у вас слишком много работы на вашем компьютере для объема оперативной памяти.

Наконец, неизбежен некоторый шум, потому что каждый из этих multiply вызовов генерирует мусор, и сборщик мусора должен будет работать, чтобы справиться с этим.


Наконец, наконец, если вы вручную запускаете сборщик мусора (или увеличиваете размер кучи), чтобы «сгладить» точки данных, то на самом деле вы скрываете одну из затрат на multiply вызовов. Полученные графики выглядят красиво, но вводят в заблуждение:

  • Шумность отражает то, что будет происходить в реальной жизни.
  • Истинная стоимость multiply фактически включает амортизированную стоимость работы сборщика мусора для работы с мусором, сгенерированным вызовом.

Чтобы получить измерения, которые отражают то, как BigInteger ведет себя в реальной жизни, вам нужно запустить тест большое количество раз, вычислить среднее время и подогнать кривую к средним точкам данных.

Помните, настоящая цель игры - получить научно обоснованные результаты, а не плавную кривую.

person Stephen C    schedule 24.05.2012

Если вы выполняете микробенчмарк, вы должны сначала «разогреть» JVM, чтобы позволить JIT оптимизировать код, а затем вы можете измерить производительность. В противном случае вы измеряете работу, выполненную JIT, и это может изменить результат при каждом запуске.

«Шум» возникает, вероятно, из-за того, что кэш ЦП превышен, и производительность начинает ухудшаться.

person Emmanuel Bourg    schedule 24.05.2012
comment
Хорошо, но случай с непрогретой JVM находится в самом начале симуляции. Позже можно перейти в разогретое состояние. Но шум находится в конце моделирования, а не в начале - person Jan Ajan; 25.05.2012