«

»

Май 16 2014

Оптимизация кода компилятором FreePascal`я

Мы все привыкли слышать о том, что Pascal медленнее C от 2-х до 5-ти раз. Это мнение глубоко укоренилось в головах большей части людей. Однако это не совсем так. Во первых корректно сравнивать конкретные компиляторы, а не языки в целом (т.к. у обоих языком компиляторов хватает). Во вторых в подавляющем большинстве тестов которые я видел сравнения проводятся некорректно, т.к. для того же gcc обычно выставляются параметры вроде таких: -c -O3 -fomit-frame-pointer -march=native -mfpmath=sse -msse3, в то время как для FPC бывает даже простое -O1 (при котором запрещено даже использование регистров для хранение переменных). Даже в лучшем случае мы просто имеет -O3. Например, тест N-Body с известного сайта benchmarksgame.alioth.debian.org для С код компилируется с приведёнными выше ключами, FPC получает лишь ключи -O3 -XXs.

C-шный вариант занимает 5.78с на моём оборудовании, FPC-шный – 5.847с (на сайте гордо красуется 20.81 и 34.75 секунд соответственно). Я не знаю, как они там меряют (может быть используют какой-то древний FPC), но результат вопиющий (кстати, для FPC с ключом -O1 получается 9с). Кроме того у FPC тоже есть оптимизационные ключи вроде “-CpCOREI” и “-CfSSE3”, которые почему-то никто не удосуживается устанавливать.

Мало того, у FPC есть одна неприятная особенность. Многие оптимизации включаются отдельными ключами, при этом про них почти нигде не пишут. Самыми вопиющими из них я считаю эти:

  • -OoUSERBP – разрешает использовать соответствующий регистр для вычислений в функциях в выброшенным стекфреймом
  • -OoAUTOINLINE – разрешает компилятору самому инлайнить функции при необходимости (без необходимости ручного указание inline соотв. функциям)
  • -OoLOOPUNROLL – разворачивает циклы (до 5 итераций)
  • -OoSTRENGTH – позволяет компилятору делать оптимизации таких вещей, как обращение к элементам массива в цикле (ниже будет подробнее)

Так что, судя о производительности компиляторов, давайте будет делать это объективно. Я не буду спорить, что способности специализированных компиляторов C/C++, вроде интеловского будут впереди из-за их способностей к векторизации. Однако надо чётко понимать, что такого кода обычно крайне немного, это раз. Каким бы ни был умным компилятор, он всё равно проиграет человеку в таком коде, это два.

Небольшой пример работы ключа -OoSTRENGTH

Функция:

Procedure Test;
Var
  I, J: WordPR;
  X : Array [0..4, 0..4] of WordPR;
Begin
 For I := 0 to 4 do
 For J := 0 to 4 Do
 X[I, J] := 0;
End;

ASM-листинг без  -OoSTRENGTH:

	leaq	-200(%rsp),%rsp
	movq	$0,%rcx
	subq	$1,%rcx
.Lj7:
	addq	$1,%rcx
	movq	$0,%rdx
	subq	$1,%rdx
.Lj10:
	addq	$1,%rdx
	imulq	$40,%rcx,%rax
	leaq	(%rsp,%rax),%rax
	movq	$0,(%rax,%rdx,8)
	cmpq	$4,%rdx
	jb	.Lj10
	cmpq	$4,%rcx
	jb	.Lj7
	leaq	200(%rsp),%rsp
	ret

ASM-листинг с  -OoSTRENGTH:

	leaq	-200(%rsp),%rsp
	movq	%rsp,%rax
	movq	$0,%rcx
	subq	$1,%rcx
.Lj9:
	addq	$1,%rcx
	movq	$0,%rdx
	subq	$1,%rdx
.Lj12:
	addq	$1,%rdx
	movq	$0,(%rax,%rdx,8)
	cmpq	$4,%rdx
	jb	.Lj12
	addq	$40,%rax
	cmpq	$4,%rcx
	jb	.Lj9
	leaq	200(%rsp),%rsp
	ret

Добавить комментарий