Javier Luis Lopez Ответов: 2

Является ли использование встроенных функций и функций #define устаревшим?


Я обычно вижу в высокоскоростном кодировании использование #define и встроенных функций для ускорения программ.
Я сделал несколько тестов скорости, и в результате эти усилия бесполезны в windows.
#Define полезен только для меня в linux, но я тестировал его на старом компьютере с частотой 1 ГГц.

Вот результаты:
Цитата:
Windows7 Intel 3,5 ГГц
Режим релиза:
#define = 1.009 наносекунд/операция
функция = 0,997 наносекунды / операция
встроенная функция = 1,031 наносекунды / операция

Режим отладки:
#define = 3,467 наносекунды / операция
функция = 11,09 наносекунд/операция
встроенная функция = 11,81 наносекунды / операция

Линукс АМД 1ГГц:
#define = 10,06 наносекунды / операция
функция = 14,28 наносекунды / операция
встроенная функция = 13,20 наносекунд/операция


Что я уже пробовал:

Он был скомпилирован в linux с использованием: gcc-std=c++11 -lstdc++ - o prue define_timing.cpp

Я попробовал следующий код:

#include <iostream>
#include <chrono>

using namespace std;

#define INLIMIT2(x,xmin,xmax) ( (x)<(xmin) ? (xmin) : ((x)<(xmax) ? (x) : ((xmax)))) 
double inlimit2(double x, double xmin, double xmax)
{
	if (x < xmin)
		return xmin;
	else if (x >= xmax)
		return xmax;
	return x;
}


inline double inlimit3(double x, double xmin, double xmax)
{
	if (x < xmin)
		return xmin;
	else if (x >= xmax)
		return xmax;
	return x;
}

int main()
{
	const int top=1000000000;
	double *x=new double[top];
	int i;
	for (i = 0; i < top; i++) x[i] = 1.01*i;
	time_t ini, fin;
	double x2 = 0.0;

	cout << "Test using #define:" << endl; x2 = 0.0;
	ini = clock();
	for (i = 0; i < top; i++) x2 += INLIMIT2(x[i], 10.0, 100.0);
	fin = clock();
	cout << "Time/op=" << 1e9 / top*(1.0*fin - ini) / CLOCKS_PER_SEC << " nanoseconds/operation" << endl;
	cout << "Result=" << x2 << endl;

	cout << "Test using function:" << endl; x2 = 0.0;
	ini = clock();
	for (i = 0; i < top; i++) x2 += inlimit2(x[i], 10.0, 100.0);
	fin = clock();
	cout << "Time/op=" << 1e9 / top*(1.0*fin - ini) / CLOCKS_PER_SEC << " nanoseconds/operation" << endl;
	cout << "Result=" << x2 << endl;

	cout << "Test using inline function:" << endl; x2 = 0.0;
	ini = clock();
	for (i = 0; i < top; i++) x2 += inlimit3(x[i], 10.0, 100.0);
	fin = clock();
	cout << "Time/op=" << 1e9 / top*(1.0*fin - ini) / CLOCKS_PER_SEC << " nanoseconds/operation" << endl;
	cout << "Result=" << x2 << endl;

	delete x;
	cout << "=== END ===" << endl; getchar();
	return 1;
}

2 Ответов

Рейтинг:
6

CPallini

Я полагаю, это зависит от оптимизации компилятора.
В качестве общего совета используйте самый чистый код, который вы можете использовать, и применяйте "ручную" оптимизацию только тогда, когда требуется ускорение (и, возможно, достигается).


Javier Luis Lopez

Может быть, это зависит также от процессора или графического процессора?
Некоторые процессоры позволяют выполнять операции параллельно, поэтому, возможно, некоторые оптимизации избегают или позволяют использовать SSE, SSE2 или любой другой

CPallini

Да.

Рейтинг:
18

Jochen Arndt

Современные компиляторы трактуют inline ключевое слово как предложение. Они могут создавать функции с этим ключевым словом как встроенные или нет, а также могут создавать функции без этого ключевого слова как встроенные.

Если вы действительно хотите знать, что делает компилятор, вы должны проверить вывод сборки (опция GCC -S и /FA вариант с компилятором MS).

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

При использовании макросов у вас будет встроенный код. Таким образом, вы можете использовать макросы вместо функций для принудительной встраивания.

Но имейте в виду недостатки макросов (склонность к нежелательным побочным эффектам, отсутствие проверки типов, худшая читабельность кода).

Если вы не используете макросы, вы все равно можете гарантировать, что компилятор генерирует больше встроенного кода, оптимизируя скорость, а не размер (MS compiler: /O2; GCC: не использовать -Os; использовать -O2 или -O3).

GCC не будет создавать встроенные функции, если не задана оптимизация, и только очень немногие (если таковые имеются) с -O и -O1 Поскольку вы не указали ни одного варианта оптимизации, ваша сборка Linux не использовала встроенные функции (разница во времени может быть вызвана неопределенностью). Я предлагаю повторить ваши измерения после построения с помощью -O2 или -O3.