LINUX.ORG.RU

Скорость вызова функций в C


0

0

В программе несколько однотипных функций, вычисляющих интеграл методом Симпсона.

double idens(double x,double y) {
        int steps,c; 
        double rn, sumn, sprev, steplength, extra;
    extra=2*dens(x,y,0.5);
    sumn=dens(x,y,0)+dens(x,y,1)+2*extra;
    steps=1;
    do {
         steps*=2; sprev=sumn; steplength=(1.0/steps/2); sumn-=extra; extra=0;
         for (c=0; c<steps; c++){ 
             extra+=dens(x,y,c*2+1)*steplength)*2; }
         sumn+=extra*2;
         rn=(sumn/6.0/steps-sprev/3.0/steps); 
         if (rn<0) {rn=-rn;};
    } while (rn>epsilon);
    return sumn;}

Различаются они только вызываемой подинтегральной функцией вида double dens(double x, double y, double z)

Вопрос: имеет ли смысл обозначить dens как переменную и заменить все интегрирующие функции на одну? Или это замедлит программу?

Заранее спасибо.
★★★

[offtop]Было бы неплохо сразу, при запуске, составить таблицу решений, а потом брать значения из неё, а не вычислять каждый раз новое значение в цикле.[/offtop]

anonymous
()

> имеет ли смысл обозначить dens как переменную и заменить все интегрирующие функции на одну?

Имеет. Я вообще не очень понимаю, зачем тебе несколько разных функций, которые реализуют один и тот же метод.

Uncle_Theodore ★★
()
Ответ на: комментарий от Uncle_Theodore

> Имеет.

Спасибо.

> Я вообще не очень понимаю, зачем тебе несколько разных функций, которые реализуют один и тот же метод.

Если dens(x,y,z), то в каждой -- своя формула. Если idens(x,y) -- неправильно понял про замедление при вызове функции через переменную.

olegd ★★★
() автор топика
Ответ на: комментарий от Uncle_Theodore

> Имеет. Я вообще не очень понимаю, зачем тебе несколько разных функций, которые реализуют один и тот же метод.

А вы например вкурсе почему плюснутый std::sort быстрее пуре-си qsort-а? :)

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

fmj
()
Ответ на: комментарий от anonymous

> Было бы неплохо сразу, при запуске, составить таблицу решений, а потом брать значения из неё, а не вычислять каждый раз новое значение в цикле.

В смысле? Для каждой комбинации x,y,z dens(x,y,z) вычисляется всего один раз, если я ничего не напутал. Всего точек x,y -- от 250 000 до 5 000 000. Заранее всё вычислить?

Или что имеется в виду под таблицей решений?

olegd ★★★
() автор топика
Ответ на: комментарий от fmj

> вызов функции через указатель -- дорогая неоптимизируемая операция,

Насколько дорогая?

> пишите либо макросами

Которые препроцессор потом развернёт в несколько однотипных функций, как сейчас?

> либо на плюсы с темплейтами переходите (что разумнее будет).

Можно ссылку на пример?

Спасибо.

olegd ★★★
() автор топика
Ответ на: комментарий от olegd

>> вызов функции через указатель -- дорогая неоптимизируемая операция,

> Насколько дорогая?

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

tailgunner ★★★★★
()
Ответ на: комментарий от olegd

> Насколько дорогая?

AFAIK остановка/сброс конвейра част происходят, на таких вызовах, а это жутко дорого.

> Которые препроцессор потом развернёт в несколько однотипных функций, как сейчас?

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

> Можно ссылку на пример?


template<double FN(double)> 
double doSOmething(double x, double y)
{
       return x*y + FN(x*y);
}

res = doSomething<RealFunc>(1,2);


fmj
()
Ответ на: комментарий от fmj

>> Насколько дорогая?

> AFAIK остановка/сброс конвейра част происходят, на таких вызовах

При неправильно предсказанном переходе.

> а это жутко дорого.

На процессоре с жутко длинным конвейером (P4).

В общем, нужно мерять.

tailgunner ★★★★★
()
Ответ на: комментарий от fmj

> AFAIK остановка/сброс конвейра част происходят, на таких вызовах, а это жутко дорого.

Хотя может тут я и гоню, но в целом -- inline делает свое дело, посмотрите например:

http://www.tilander.org/aurora/2007/12/comparing-stdsort-and-qsort.html

fmj
()
Ответ на: комментарий от fmj

>да какая собств. разница, вот версия для Ъ: http://theory.stanford.edu/~amitp/rants/c++-vs-c/

Я думаю ключевым моментом там является это:

Andrew Robb, using a different system, was unable to reproduce the results; on his system, qsort was faster than std::sort. He also has a merge sort routine that only works with arrays (not STL vector and deque), but sorts faster than std::sort. This also shows that if you work hard, you can get something faster than STL.

Так что все эти тесты ничего не говорят.

koTuk
()
Ответ на: комментарий от koTuk

> Аргументы закончились и начались обычные наезды ?

Блин, баклан, ну сравни сам std::sort хоть тупо, для обычного int массива, и qsort.

#include <stdlib.h>
#include <time.h>
#include <algorithm>

enum { NR = 10000000 };
int arrA[NR];
int arrB[NR];

int cmpC(const void *a, const void *b)
{
        return *(int*)a - *(int*)b;
}

int main()
{
        for (int i=0; i<NR; i++)
        {
                arrA[i] = arrB[i] = rand();
        }


        time_t t1 = time(NULL);

        qsort(arrA, NR, sizeof(int), cmpC);

        time_t t2 = time(NULL);

        std::sort(&arrB[0], &arrB[NR]);

        time_t t3 = time(NULL);

        printf("pure C qsort:\t%d\nC++ std::sort:\t%d\n", t2-t1, t3-t2);
}

$ g++ -Os  1.cpp -o 1 && ./1 

pure C qsort:	4
C++ std::sort:	1


$ g++ --version 
i686-apple-darwin9-g++-4.0.1 (GCC) 4.0.1 (Apple Inc. build 5483)
Copyright (C) 2005 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ uname -a
Darwin mac46.local 9.2.0 Darwin Kernel Version 9.2.0: Tue Feb  5 16:13:22 PST 2008; root:xnu-1228.3.13~1/RELEASE_I386 i386


fmj
()
Ответ на: комментарий от fmj

> pure C qsort: 4

> C++ std::sort: 1

Похоже, топикстартеру вполне можно использовать указатель, если у него функции будут посложнее одного вычитания целых чисел :)

tailgunner ★★★★★
()
Ответ на: комментарий от olegd

Все кто советует заранее вычислять таблицу решений плохо понимают что если нужна высокая точность а следовательно и большая таблица то этот вариант КРАЙНЕ неадекватен потому что одно значение в таблице 4 или 8 байтов, а далее помножаем на размер таблицы и ... сколько у вас эти таблички места займут? Сейчас у вас 5миллионов а завтра нужно будет 500 миллионов и? По опыту скажу так - если вы уверены что вам НЕ прижмет повышать точность (делать больше разбиений) то делайте таблички если нет то лучше не надо ибо как только данные для счетной программы вываливаются из ОЗУ в своп все считайте времени выполнения полный пи..ц оно растет как минимум в 10(для BSD) а то и в 100(Для window) раз, и тут дешевше лишний раз посчитать функцию...

anonymous
()
Ответ на: комментарий от fmj

#define DOSMTH(f, x, y) (x*y + f(x*y))

double my_f(double x)
{
return x / 2.0;
}

main()
{
printf("%f\n", DOSMTH(my_f, 1.7, 3.9));
}

seiken ★★★★★
()
Ответ на: комментарий от fmj

bash-3.2$ cat ./1.cpp
#include <stdlib.h>
#include <time.h>
#include <algorithm>

enum { NR = 100000000 };
int arrA[NR];
int arrB[NR];

int cmpC(const void *a, const void *b)
{
        return *(int*)a - *(int*)b;
}

int main()
{
        for (int i=0; i<NR; i++)
        {
                arrA[i] = arrB[i] = rand();
        }


        time_t t1 = time(NULL);

        qsort(arrA, NR, sizeof(int), cmpC);

        time_t t2 = time(NULL);

        std::sort(&arrB[0], &arrB[NR]);

        time_t t3 = time(NULL);

        printf("pure C qsort:\t%d\nC++ std::sort:\t%d\n", t2-t1, t3-t2);
}

bash-3.2$ g++ 1.cpp -o 1 && ./1 
pure C qsort:   51
C++ std::sort:  62

bash-3.2$ g++ -v
Using built-in specs.
Target: i686-pc-linux-gnu
Configured with: ../gcc-4.2.4/configure --prefix=/usr --libexecdir=/usr/lib --enable-languages=c,c++,objc --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-shared --disable-nls --with-x=no
Thread model: posix
gcc version 4.2.4 (CRUX)

bash-3.2$ uname -a
Linux dell 2.6.25.4-MY #1 SMP PREEMPT Wed May 28 12:17:18 UTC 2008 i686 Genuine Intel(R) CPU T2300 @ 1.66GHz GenuineIntel GNU/Linux


koTuk
()
Ответ на: комментарий от koTuk

> bash-3.2$ g++ 1.cpp -o 1 && ./1

Ты оптимизацию случайно не включил или намеренно? Ее отсуствие все бы объяснило - Си-вариант оптимизации не поддается, а Си++ - очень даже.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

> Ты оптимизацию случайно не включил или намеренно? Ее отсуствие все бы объяснило - Си-вариант оптимизации не поддается, а Си++ - очень даже.

Я думаю он это намеренно, видно же, что это тролль

fmj
()
Ответ на: комментарий от fmj

ыы...

результаты с linux машины, с 1-в-1 таким-же Core 2 Duo что и у мака:

pure C qsort: 46

C++ std::sort: 17

$ g++ --version

g++ (GCC) 4.1.2 20061115 (prerelease) (SUSE Linux) Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$uname -a

Linux testhost 2.6.18.2-34-default #1 SMP Mon Nov 27 11:46:27 UTC 2006 i686 i686 i386 GNU/Linux

Там зузя 10.2 старая. Что не так, почему сортировка в 10 раз медленее чем на маке работает ? Неужто особенности VM Linux-ового, по сравнению с Mach-овским, такую разницу дают?

fmj
()
Ответ на: комментарий от fmj

>Что не так, почему сортировка в 10 раз медленее чем на маке работает ? Неужто особенности VM Linux-ового, по сравнению с Mach-овским, такую разницу дают?

Если ты из моего поста взял - там нолик добавлен NR = 100000000.

koTuk
()
Ответ на: комментарий от fmj

>Andrew Robb, using a different system, was unable to reproduce the results

Похоже он на sparc-е тестил :) Вообще троллить я не собирался - мне казалось что многочисленные вызовы не так сильно скажутся на производительности.

koTuk
()

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

anonymous
()
Ответ на: комментарий от anonymous

> Реализуй самым простым и понятным способом,

Для меня самый понятный и читаемый способ -- через указатели.

olegd ★★★
() автор топика
Ответ на: комментарий от tailgunner

> Похоже, топикстартеру вполне можно использовать указатель, если у него функции будут посложнее одного вычитания целых чисел :)

10-20 арифметических действий, экспонента, арктангенс.

olegd ★★★
() автор топика
Ответ на: комментарий от tailgunner

>> а это жутко дорого.

> На процессоре с жутко длинным конвейером (P4).

Как насчёт Celeron D? На другой машине Athlon.

> В общем, нужно мерять.

5 000 000 точек, с инлайновой подинтегральной функцией 15 секунд, с вызовом по указателю 17. Жить можно. Процессор -- Athlon 64 в 32-битном режиме. На Celeronах будет сильно отличаться?

olegd ★★★
() автор топика
Ответ на: комментарий от fmj

> Так це же компилятор,

Не считаю недостатком, просто спросил как оно работает.

>> Можно ссылку на пример?

>template<double FN(double)>

Спасибо.

olegd ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.