Производительность грубого хеширования C ++ Java

0

Я внедрил brute-forcer для md5 как в C++, так и в Java, и у меня возникли вопросы о том, почему их эффективность отличалась так же, как и она.
Данные и график сложности (E ^ длина пароля) и время здесь: http://i.imgur.com/hckCe8f.png
Пароли были простыми буквами "b", чтобы заполнить длину

В C++ я использовал эту реализацию md5: zedwood.com/article/cpp-md5-функция
А на Java я использовал вторую реализацию на этом сайте: http://www.asjava.com/core-java/java-md5-example/

В рекурсивной реализации C++ мой код для цикла был выполнен в отдельном классе:

class bruteChar {
    string charset;
    char last_char;
    string str;
    string double_start;
    char reverse_charset[256];
  private:
    string next(string s)
    {
        size_t length = s.size()-1;
        if(length == 0)
        {
            if( s[0]==last_char)
                return double_start;
            return string(1, charset[reverse_charset[s[length]]+1]);
        }
        if(s[length] == last_char)
            return next(s.substr(0,length))+charset[0];
        else
            return str.substr(0,length)+string(1, charset[reverse_charset[s[length]]+1]);
    };

  public:
    void start (string chars)
    {
        charset = chars;
        str=charset[0];
        last_char=charset[charset.size()-1];
        double_start=charset[0];
        double_start+=charset[0];

        for(size_t i = 0; i < charset.size(); ++i)
            reverse_charset[charset[i]]=i;
        reverse_charset[charset[charset.size()]]=0;
    }

    string next()
    {
        str=next(str);
        return str;
    }
};

В Java я использовал пользовательский класс

public class picochar {
    public static char[] charset = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); 
    int num;
    int mod;

    picochar(int init, int mod)
    {
        num = init%mod;
    }

    picochar(char init, int mod)
    {
        for(int i = 0; i < mod; i++)
        {
            if(charset[i] == init)
                num = i;
        }  
    }

    public char get()
    {
        return charset[num];
    }

    public boolean equals(char  ch)
    {
        return (get() == ch);
    }

    public void increment()
    {
        num++;
    }
}

и следующий метод

public static String next(String s) {
    int length = s.length();
    picochar pc = new picochar(s.charAt(length - 1),mod);
    if(pc.equals(picochar.charset[mod-1]))
        return length > 1 ? next(s.substring(0, length - 1)) + 'a' : "aa";
    pc.increment();
    return s.substring(0, length - 1) + pc.get();
}

Почему Java намного эффективнее при вычислении хэшей, чем C++?
Я просто использовал эффективную реализацию MD5 для Java и плохой для C++?
Я предположил, что C++ будет намного быстрее, чем Java, поскольку Java должна запускать все через JVM, а C - изначально.

Однако Java намного превосходит решение C++. Если это было просто из-за плохого кодирования в моей программе C++, как бы я это исправить?

Отредактированный для удаления разнородной C++ программы, теперь оба решения цикла рекурсивно.

Я сделал некоторое время на то, сколько времени прошло, чтобы пройти без хэширования, и здесь Java в два раза быстрее, чем C, что было объяснено @Dunes. При перекодировке, чтобы не рекурсивно использовать substr() и вместо этого мутировать исходную строку, C был примерно в два раза быстрее, чем Java.

Я сделал несколько тестов, сколько времени занимает хэш "привет" 1 << 25 раз, и нашел что-то странное - Java, казалось, "разогревался" намного быстрее, и хотя медленнее сначала было бы быстро догнать реализацию C,
C++ будет иметь аналогичный прирост производительности после того, как хэширует в течение нескольких секунд, но выигрыш был нигде рядом с Java.

Так почему же разминка Java лучше?

  • 2
    Я бы попытался сделать код более похожим. C ++ и Java не должны выглядеть так по-разному. Эти различия, вероятно, объясняют разницу в производительности.
  • 0
    Ну, как вы сказали, вам нужно сравнить те же реализации. С ++, вероятно, будет быстрее в целом, если все сделано правильно. И примечание: это не только из-за JIT.
Показать ещё 2 комментария
Теги:
performance
brute-force
md5

2 ответа

0
Лучший ответ

Оказывается, я использовал неэффективную реализацию md5.
Здесь время, затраченное на вычисление 2 27 хешей по сравнению с временем, которое потребовалось openssl

openssl v1
17.4911

openssl v2
14.9546

custom
291.201
1

Похоже, что реализация c++ настолько медленная, потому что вы передаете строки по значению. Это каждый раз, когда вы вызываете метод со строковым аргументом или возвращаете строку, программа должна создать совершенно новую копию всей строки.

Принимая во внимание, что, поскольку Java имеет неизменяемые строки, он может уйти с прохождением разных видов одной и той же строки. String.substring не копирует массив String.substring символов. Вместо этого новый строковый объект просто отслеживает начальный индекс и длину по отношению к массиву опорных символов. Когда подстрока используется неразумно, это может привести к утечкам памяти - представление одного символа сохранит исходный миллионный массив поддержки массива до тех пор, пока он существует.

  • 0
    Ах! Я пытался сделать две петли максимально похожими, но не знал, как они работают под капотом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню