1 Востаннє редагувалося YurkoFlisk (14.06.2016 17:10:17)

Тема: Проблема з шаблонами

Доброго дня. Недавно зіткнувся з досить дивною проблемою, пов'язаною з шаблонами. Створив окремий проект(Visual C++ 2015), щоб максимально загально її протестувати. Ось код:

#include <fstream>
#include <chrono>

using namespace std;

template<int Foo>
int g(int num)
{
    return f<Foo>(num);
}
template<int Foo>
int f(int num)
{
    if (num == 0)
        return Foo;
    return num + f<Foo>(num - 1);
}
int foo(void)
{
    f<1>(0); // Fix
}

int main(void)
{
    int a(0);
    ofstream out("log.txt");
    for (int i = 0; i < 5; ++i)
    {
        auto start = chrono::high_resolution_clock::now();
        for (int i = 0; i < 70000; ++i)
            a += g<1>(i);
        auto end = chrono::high_resolution_clock::now();
        out << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms elapsed " << a << '\n';
    }
    out.close();
    return 0;
}

Проблема в тому, що якщо закоментувати рядок Fix у функції foo, швидкодія програми несподівано погіршується. Ось результат роботи програми(вміст log.txt) спочатку:

Прихований текст
5669ms elapsed 652015240
5769ms elapsed 1304030480
5650ms elapsed 1956045720
5717ms elapsed -1686906336
5675ms elapsed -1034891096

і після коментування рядка Fix:

Прихований текст
6538ms elapsed 652015240
6524ms elapsed 1304030480
6545ms elapsed 1956045720
6520ms elapsed -1686906336
6514ms elapsed -1034891096

Чому так відбувається? Наскільки я розумію, цей рядок не має впливати на роботу програми. Тут якась помилка в коді, чи це можуть бути особливості компілятора?

Подякували: leofun011

2

Re: Проблема з шаблонами

Поки що не зрозумів в чому проблема, але ось кинулось в очі що функція int foo(void) нічого не повертає

int foo(void)
{
    f<1>(0); // Fix
}

З.І. Тьху, так вона ж ніде й не використовується.

Подякували: YurkoFlisk1

3

Re: Проблема з шаблонами

1) Коли я намагався скомпілювати, то була помилка: функція int foo(void) не містить return.
В себе я поставив void foo(void).

2) Цей код:

for (int i = 0; i < 70000; ++i)
    a += g<1>(i);

Буде формувати величезний стек викликів функцій (близько 140000) і це не нормально. Тому хто тестує, доведеться або збільшити максимальний розмір стеку (а це не бажано), або зменшити діапазон змінної i.

3) В мене теж програма виконується швидше, коли є явний виклик функції f<1>(0) (в мене VS2013).
Думаю справа тут в тому, що коли компілятор бачить f<1>(0), то відповідна реалізація template'а вже готова до використання. А коли його нема, то спочатку формується опис, а потім кожен виклик перенаправляється на реалізацію. Це лише моя думка, і вона може бути неправильна.

Попробуйте в іншому порядку:

template<int Foo>
int f(int num)
{
    if(num == 0) return Foo;
    return num + f<Foo>(num - 1);
}
template<int Foo>
int g(int num)
{
    return f<Foo>(num);
}

В мене так пішло швидше і без f<1>(0).

Подякували: YurkoFlisk1

4

Re: Проблема з шаблонами

У мене однаково швидко в обох випадках. А які у вас налаштування оптимізації стоять в проекті?

Подякували: YurkoFlisk1

5

Re: Проблема з шаблонами

Щодо функції foo, то тут я протупив, хоча в мене і з int foo(void) компілюється. В принципі, можна і без неї обійтись, тут важливо саме, що десь у коді явно викликається екземпляр f<1>.
Щодо стеку викликів, то про це я не подумав, але тут пишуть, що за замовчуванням його розмір 1МБ. Тут, здається, цього має вистачити.
Зміна порядку визначення функцій f і g в мене на результат не впливає, але я спробував узагалі прибрати шаблони і функцію g:

Прихований текст
#include <fstream>
#include <chrono>

using namespace std;

int f(int num)
{
    if (num == 0)
        return 1;
    return num + f(num - 1);
}

int main(void)
{
    int a(0);
    ofstream out("log.txt");
    for (int i = 0; i < 5; ++i)
    {
        auto start = chrono::high_resolution_clock::now();
        for (int j = 0; j < 70000; ++j)
            a += f(j);
        auto end = chrono::high_resolution_clock::now();
        out << chrono::duration_cast<chrono::milliseconds>(end - start).count() << "ms elapsed " << a << '\n';
    }
    out.close();
    return 0;
}

В цьому випадку швидкодія така ж погана, як і при шаблонах без явного виклику f<1>.
Налаштування оптимізації:

Прихований текст

https://pic.co.ua/images/2016/06/15/234ad73c6d84d7c48d6a07e33d9ebb82.png

Подякували: leofun011

6 Востаннє редагувалося Yola (15.06.2016 16:07:52)

Re: Проблема з шаблонами

Я маю

VS Community 2015
Version 14.0.24720.00 Update 1

І ніякої різниці у використанні пам'яті, див зображення.

Post's attachments

memory.png 41.52 kb, 117 downloads since 2016-06-15 

Подякували: YurkoFlisk1

7

Re: Проблема з шаблонами

Я зробив діагностику з використання ЦП. При відсутності шаблонів:

Прихований текст

https://pic.co.ua/images/2016/06/15/c2fc3585b1e9a4930854d4b383a82f90.png

При шаблонах, коли немає явного виклику f<1>:

Прихований текст

https://pic.co.ua/images/2016/06/15/9324c87530e97f1b9e55d1d3a25f5880.png

При шаблонах, коли є явний виклик f<1>:

Прихований текст

https://pic.co.ua/images/2016/06/15/e92f599a68310b28b704e26d82652bdc.png

Yola написав:

Я маю

VS Community 2015
Version 14.0.24720.00 Update 1

У мене така ж версія VS.

Подякували: leofun011