Comments 25
I've profiled the «go build» variant of program (same run time with profiling code) and saw, that 94.1% of time program was in
github.com/jzelinskie/whirlpool.(*whirlpool).transform
Кастинг в Go медленный. Кошерный способ оптимизации с этом случае — вынос кастинга за пределы цикла.
Это вот здесь:
// Iterate over all the rounds.
for r := 1; r >56)] ^
_C1[byte(K[(i+7)%8]>>48)] ^
_C2[byte(K[(i+6)%8]>>40)] ^
_C3[byte(K[(i+5)%8]>>32)] ^
_C4[byte(K[(i+4)%8]>>24)] ^
_C5[byte(K[(i+3)%8]>>16)] ^
_C6[byte(K[(i+2)%8]>>8)] ^
_C7[byte(K[(i+1)%8])]
}
и
for i := 0; i < 8; i++ {
L[i] = _C0[byte(state[i%8]>>56)] ^
_C1[byte(state[(i+7)%8]>>48)] ^
_C2[byte(state[(i+6)%8]>>40)] ^
_C3[byte(state[(i+5)%8]>>32)] ^
_C4[byte(state[(i+4)%8]>>24)] ^
_C5[byte(state[(i+3)%8]>>16)] ^
_C6[byte(state[(i+2)%8]>>8)] ^
_C7[byte(state[(i+1)%8])] ^
K[i%8]
}
// Iterate over all the rounds.
for r := 1; r >56)] ^
_C1[byte(K[(i+7)%8]>>48)] ^
_C2[byte(K[(i+6)%8]>>40)] ^
_C3[byte(K[(i+5)%8]>>32)] ^
_C4[byte(K[(i+4)%8]>>24)] ^
_C5[byte(K[(i+3)%8]>>16)] ^
_C6[byte(K[(i+2)%8]>>8)] ^
_C7[byte(K[(i+1)%8])]
}
и
for i := 0; i < 8; i++ {
L[i] = _C0[byte(state[i%8]>>56)] ^
_C1[byte(state[(i+7)%8]>>48)] ^
_C2[byte(state[(i+6)%8]>>40)] ^
_C3[byte(state[(i+5)%8]>>32)] ^
_C4[byte(state[(i+4)%8]>>24)] ^
_C5[byte(state[(i+3)%8]>>16)] ^
_C6[byte(state[(i+2)%8]>>8)] ^
_C7[byte(state[(i+1)%8])] ^
K[i%8]
}
А, понятно. Тогда я согласен с комментарием mc_dir ниже. Тяжелую часть можно вынести в C, через cgo. Правда это слегка подпортит жизнь тем, кто собирает Go под Windows.
При сборке с оптимизациями особого смысла это более не имеет. Да и запарно выносить, мне кажется.
У gccgo свои заморочки, например goroutines там становятся полноценными потокоми, иными словами теряется вся прелесть Go.
пруф, пожалуйста, в студию.
Цитата из The Go Programming Language Phrasebook:
FAQ также утверждает, что:
Я не в курсе значит ли это, что и переключение между goroutines кооперативное под gccgo или нет.
The most obvious is that gccgo uses operating system threads to implement goroutines, and will not use segmented stacks in all configurations. This means that creating a goroutine is as expensive as creating a thread in C.
FAQ также утверждает, что:
The gccgo compiler implements segmented stacks on Linux only, supported by recent modifications to the gold linker.
Я не в курсе значит ли это, что и переключение между goroutines кооперативное под gccgo или нет.
В посте ранее добавил ссылку:
blog.golang.org/gccgo-in-gcc-471
blog.golang.org/gccgo-in-gcc-471
Желтовато получается.
В php hash (whirlpool) реализован на С [тыц], и компилируется со всеми необходимыми оптимизациями (в примере так полагаю эту функцию и тестируют),
когда в GO whirlpool реализован на самом GO [тыц]
Если вы уже хотите два языка сравнить, так воаля перепишите whirlpool на чистый PHP и сравните…
В php hash (whirlpool) реализован на С [тыц], и компилируется со всеми необходимыми оптимизациями (в примере так полагаю эту функцию и тестируют),
когда в GO whirlpool реализован на самом GO [тыц]
Если вы уже хотите два языка сравнить, так воаля перепишите whirlpool на чистый PHP и сравните…
Видимо, скромного примечания в скобках оказалось недостаточно. Сейчас подправлю.
Заголовок статьи обещал помочь ускорить Go. Результат статьи — ускорение работы. Автор не пытался возвысить один язык над другим, более того, в итоге код на Go сработал почти со скоростью кода на Си/ПХП. Не увидел здесь желтизны.
Да, и про сравнение. С самого начала было понятно, что там шустрый Сишный модуль. Тем не менее такой огромный проигрыш не мог не расстроить меня. Т.е. сравнение в принципе проводилось ради того, чтобы выяснить, это whirlpool такой медленный или реализация/язык.
Не всем понятно где какой модуль и что использует. И похоже когда я писал коментарий название у статьи было другое. А за освещение возможности оптимизации компиляции GO спасибо.
Некоторые пакеты в Go ещё недостаточно оптимизированы. Например тот же regexp обещали ускорить в 1.3.
Кстати, какой версии Go использовался?
Кстати, какой версии Go использовался?
Всетаки лучше смотреть на картинку в целом, а не на частный случай коня в вакууме.
benchmarksgame.alioth.debian.org/u64q/benchmark.php?test=all&lang=go&lang2=php&data=u64q
benchmarksgame.alioth.debian.org/u64q/benchmark.php?test=all&lang=go&lang2=php&data=u64q
Были проблемы с gccgo, когда использовал горутины. Решается использованием линкера
Но большие пакеты так собирать не приходилось. Так что будьте осторожны. Ещё хочу отметить, что в версии gccgo (Ubuntu 4.9.1-0ubuntu1) 4.9.1 стрип (
Помимо всего вышесказанного, если использовать в своих программах пакет
gold
замест ld
(в binutils 2.22+ он есть). У меня gccgo собран из сырья, версия 4.10.0 20140719 (experimental). Рекомендую, т.к. более новая. Насчёт флагов я лично не мелочусь:go build -compiler gccgo -gccgoflags "-march=native -Ofast -pipe -fomit-frame-pointer -fuse-ld=gold -Wl,--strip-all"
Но большие пакеты так собирать не приходилось. Так что будьте осторожны. Ещё хочу отметить, что в версии gccgo (Ubuntu 4.9.1-0ubuntu1) 4.9.1 стрип (
-Wl,--strip-all
) портит всё. Сама по себе опция -Ofast
считается не рекомендуемой (gentoo вики), а вот насчёт -O3
vs. -O2
скажу прямо — используйте -O3
для узких мест не стесняясь. Мои исследования ассемблерного листинга с этими флагами показали меньший размер и эффективное использование хвостовой рекурсии с флагом -O3
. Не мешало бы добавить, что простора для жёсткого «инлайнинга» в моём примере у компилятора не было (что значит, при иных раскладах размер может и увеличиться).Помимо всего вышесказанного, если использовать в своих программах пакет
syscall
, то gccgo (упомянутых выше версий) выдаст ошибку — такие пакеты компилируются только golang-go (или нужно подождать патчей). Ну и разумеется не получиться использовать плюшки go 1.4 (что впрочем не сильно напрягает).Так-то уже и LLVM с Go потихоньку дружит (щёлк).
Sign up to leave a comment.
Как ускорить программу на Go