Как стать автором
Поиск
Написать публикацию
Обновить

Комментарии 21

НЛО прилетело и опубликовало эту надпись здесь
Насколько же провокационной моя статья оказалась. Молодцы :)
Не провокационная, а на редкость полезная и познавательная :)
а можно узнать по поводу причины сортировки предикатов?
гитхаб

отключение данной сортировки уменьшает время выборки с 33ms до 15ms
В этой программе (на примитивном уровне) показывается работа SQL оптимизатора. Предикаты сортируются по селективности — чем меньше мы записей выберем с участием этого предиката, тем раньше мы должны его применить.
Если в app.java поправить
//27 строка
if(random.nextBoolean()) { finder = finder.withAmount(0, 0); } 
на 
if(random.nextBoolean()) { finder = finder.withAmount(0, 1000000); }
и 
//35 строка
if(random.nextBoolean()) { finder = finder.withCode(rr, rr + 5); }
на
if(random.nextBoolean() || true) { finder = finder.withCode(rr, rr + 5); }

мы ухудшим возможность отсечения ненужных строк по amount. Без сортировки предикатов amount так и останется первым и ухудшит общее время выполнения, а с сортировкой уйдет на вторую позицию.
с одной стороны я понимаю ЗАЧЕМ это все сделано, но цитируя TheShade:

– “Real world strikes back!”
– Исследуем взаимодействие софта с железом на типичных данных
• Производительность уже нельзя предсказать
• Производительность можно только измерить

замерил 20ms с отключенной сортировкой vs 31ms с включенной

p.s. конечно по хорошему нужно допилить jmh, но пока в качестве костыля увеличил количество прогревов

for (int i = 0; i < 100; i++) {
long millis1 = System.currentTimeMillis();
store.find2(finder);
long endMillis1 = System.currentTimeMillis();
System.out.println(«Elapsed time (warm) :» + (endMillis1 — millis1) + «ms»);
}

в итоге с отключенной сортировкой действительно первых пару раз еще выполняется быстрее, но потом выходит на стабильное значение в 30-31ms (с 17ms в первой попытке), в то время как с отключенной сортировкой опускается до 19-20ms (33ms в первой попытке).
Основоной посыл статьи не в абсолютных цифрах :). Сортировка требует времени. В вашем случае это время больше, чем выгода от перестановки предикатов. Почему это так — для ответа на этот вопрос нужно смотреть листинги работы JIT, как это сделать.
не понял, что я именно должен найти в листиге jit?
то что сортировка занимает время сравнимое со всем поиском?

по поводу кода:
0) вносим ваши изменения для матчера
1) смотрим какой порядок выбора предложен после сортировки
2) enum RecordFields { CODE, AGE, AMOUNT, GENDER, HEIGHT } // порядок который мы получим после анализа предикатов
3) отключаем сортировку
4) время поиска с оптимальным профилем 9-10ms

на этом фоне 30ms c включенной сортировкой как-то смотрится печально, так как теряем почти 20ms на ней
даже с неоптимальным профилем выдаем 20ms

если посмотреть на первоначальный вариант «профайла», то видно что там порядок полей с сортировкой и так попадает на оптимальный, т.е. тут мы теряем только 15ms на сортировку, что сравнимо с временем выполнения всего кода.

так что преждевременные оптимизации далеко не всегда идут во благо

p.s. еще есть косяк теста в том, что у нас массив полей неизменяемый и jit начинает уже подстраиваться под него =) поэтому по хорошему нужно еще и его регулярно перегенеривать, конечно если это у нас база данных, а не фиксированный набор полей.

p.p.s. как получить асм я представляю и уж если пошла такая пьянка на разминку мозгов:
тыц
в чем причина, что incrementnFieldCall так проседает относительно incrementnFieldCall2, ведь согласно логики производительность должна быть равна
баг уже зарепорчен, но вот поковырять asm вам должно быть прикольно
Я ждал этот пост!
Ну да, джит. Так, знаете ли, можно всю логику закешировать и радоваться, а то, что холодный старт занимает час, так это фигня, да?
А перед этим еще и компьютер включить надо — это вообще ужас!
Пример на C# мне ThermIt кинул в PullRequest, пока не проверял.
C#-Searching…
Затрачена на поиск по Code 0,0359041
Затрачена на поиск по AmountOfMoney 3E-07
1 stage 0,0520052 seconds.
C#-search took 0,0520052 seconds.
Found rows: 0
оно выполняется только 1 раз в процессе генерации метода,
в последующих вызовах сразу забирает из кеша полученный класс

можно конечно написать sb.append для отдельных составляющих, но тогда снижается читабельность
тогда можно было и стрингбилдер не мучать)
Вроде бы при компиляции он всё равно заменит плюсы на append…
да, заменит, но не так как вы себе представляете

sb.append("r.getAmount() >= " + p.minValue + " && r.getAmount() <= " + p.maxValue + " && ");


после компиляции будет

sb.append(
    new StringBuilder()
         .append("r.getAmount() >= ").append(p.minValue)
         .append(" && r.getAmount() <= ").append(p.maxValue)
         .append(" && ").toString()
);


в первом посте предложение про полное исключение созданий лишних объектов.
Ну я как раз так себе и представляю. Но интересный вопрос: если компилятор заменяет плюсы на стрингбилдер, может он и так умеет? Вы не проверяли? Я если честно сразу со стрингбилдером пишу, не люблю когда компилятор за меня меняет код, так что как точно это работает не знаю.
Осталось еще один зубодробительный вариант сделать: Сгенерировать на лету сишный код, собрать его через libclang на лету, а потом подгрузить и зарезолвить получившиеся символы.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации