powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / оптимизация производительности консольного приложения
25 сообщений из 26, страница 1 из 2
оптимизация производительности консольного приложения
    #38372745
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Имею консольную программу (хотя это еще вопрос, кто кого имеет :) ), выполняющую математические вычисления над структурами с данными. Каждая структура содержит массивы связей с другими структурами типа vector<Tn>. Четыре типа структур: T1 - 26шт, T2 - 100 шт, T3 - 3 шт, T4 - 1 шт:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
struct T1 
{
    ... some data ...
    std::vector<T2*> links;
}

struct T2 
{
    ... some data ...
    T1 *link;
}

struct T3
{
    ... some data ...
    std::vector<T1*> items;
}

struct T4
{
    ... some data ...
    std::map<int, T3*> items;
}

class CALC
{
public:
    static void Activate(T1* arg);
    static void Activate(T3* arg);
    static void Activate(T4* arg); <-- точка входа
};



Вычисление проводится последовательным перебором структур:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
void CALC::Activate(T4* arg)
{
	for(auto cur=arg->items.begin(),end=arg->items.end(); cur!=end; cur++)
		Activate(cur->second);
}

void CALC::Activate(T3* arg)
{
	for(int i=0,cnt=arg->items.size(); i<cnt; i++)
		Activate(arg->items[i]);
}

void CALC::Activate(T1* arg)
{
	for(int i=0,cnt=arg->links.size(); i<cnt; i++)
		... some calculations ... arg->links[i] ...
	... some calculations ... 
}



И вот, в чем проблема - аналогичная модель работает в аналогичной программе в C# почти в два раза быстрее, чем в C++!!!

Хотелось бы понять, почему так происходит.

Я начал навешивать счетчики на функции Activate и выяснил, что суммарно Activate(T4* arg) работает 22 сек, Activate(T3* arg) 13 сек, а Activate(T1* arg) работает 11 сек. Если учесть, что Activate(T1* arg) производит все вычисления, а Activate(T4* arg) и Activate(T3* arg) ничего посути не делают, кроме перебора элементов вектора и карты, то проблема в скорости доступа к элементам массива (вектора и карты) либо потери на вызове функции. Но это нонсенс - вектора должны работать быстро, а вызовы не могут так сильно тормозить. Либо я что-то упускаю из виду, либо неверно вектора использую (про карту вообще молчу - там 3 элемента и самая большая потеря по времени).

Что думаете? Я ожидаю, что программа на С++ должна работать в два раза быстрее С#, а пока получается наоборот. Нужно решить эту проблему, прежде чем двигаться дальше.

Пока идеи такие: навешать аналогичные счетчики на clr-сборку C# и сравнить результаты.
Поиграться с директивами методов: использовать что-то типа __fastcall
Заменить массивы на простой array[]
Покопаться в настройках компилятора: может собрать exe-типа релис или еще что-то

Накидывайте идеи, буду пробовать...
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38372778
sherzod_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreybs,

Приведите полный код программы. Ключи компилятора которые используете.
Так же в вашем случае в виду всего лишь трех элементов это малозначимно, но map != Dictionary.
map - O(log n)
Dictionary - O(const)

Нужен весь код, по приведенному участку не видно где может быть затык.
Кстати поток-то один?
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373013
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
sherzod_andreybs,

Приведите полный код программы. Ключи компилятора которые используете.
Так же в вашем случае в виду всего лишь трех элементов это малозначимно, но map != Dictionary.
map - O(log n)
Dictionary - O(const)

Нужен весь код, по приведенному участку не видно где может быть затык.
Кстати поток-то один?

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
//------------------------------------------------------------------------------
void CALC::Activate(TNeuron* neuron)
{
    TLink *link;
    double sumval = 0;
    for(int i=0,cnt=neuron->Inputs.size(); i<cnt; i++) {
        link = neuron->Inputs[i];
        sumval += link->_Weight * link->NeurSrc->_Outval;
    }

    double value = 0;
    double threshold = neuron->_Threshold;
    double factor = neuron->_Factor;
    switch(neuron->_Activation)
    {
    case AF_LINEAR:
    break;

    case AF_LOGISTIC:
        value = factor * sumval;
        value = 1.0 / (1.0 + exp(-value));

        if(threshold > 0)
            if(value > 1.0-threshold) value = 1;
            else
            if(value < threshold) value = 0;
    break;

    case AF_TANHYP:
    break;
    }
    neuron->_Outval = value;
}
//------------------------------------------------------------------------------
void CALC::Activate(TLayer* layer)
{
    if(layer->_Type == LR_INPUT) return;
    for(int i=0,cnt=layer->Neurons.size(); i<cnt; i++)
        Activate(layer->Neurons[i]);
}
//------------------------------------------------------------------------------
void CALC::Activate(TNet* net)
{
    for(auto cur=net->Layers.begin(),end=net->Layers.end(); cur!=end; cur++)
        Activate(cur->second);
}
//------------------------------------------------------------------------------



вот примерное определение структур:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
struct TNeuron {
    // Данные
    ...
    // Связи (ссылки)
    std::vector<TLink*> Inputs;
    std::vector<TLink*> Outputs;
    TLayer* Layer;
};
struct TLink {
    // Данные
    ...
    // Связи (ссылки)
    TNeuron* NeurSrc;
    TNeuron* NeurDst;
    TNet* Net;
};
struct TLayer {
    // Данные
    ...
    // Связи (ссылки)
    std::vector<TNeuron*> Neurons;
    TNet* Net;
};
struct TNet {
    // Данные
    ...
    // Связи (реальные объекты)
    std::map<int, TLayer*> Layers;
    std::map<int, TNeuron*> Neurons;
    std::map<int, TLink*> Links;
};



замеряем скорость так:

Код: plaintext
1.
2.
for(long count=0;count<1000000;count++)
    CALC::Activate(net);



Проект собран на базе MS Visio 2012, как консольное приложение с дефалтовыми настройками.

Настройки:
[C++]
/Yu"stdafx.h" /GS /analyze- /W3 /Zc:wchar_t /ZI /Gm /Od /Fd"Debug\vc110.pdb" /fp:precise /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /Oy- /MDd /Fa"Debug\" /EHsc /nologo /Fo"Debug\" /Fp"Debug\NeuroNet.pch"
[Компилятор]
/OUT:"D:\Private\Mongoose3\Projects\Console\NeuroNet\Debug\NeuroNet.exe" /MANIFEST /NXCOMPAT /PDB:"D:\Private\Mongoose3\Projects\Console\NeuroNet\Debug\NeuroNet.pdb" /DYNAMICBASE "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "comdlg32.lib" "advapi32.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "odbc32.lib" "odbccp32.lib" /DEBUG /MACHINE:X86 /INCREMENTAL /PGD:"D:\Private\Mongoose3\Projects\Console\NeuroNet\Debug\NeuroNet.pgd" /SUBSYSTEM:CONSOLE /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"Debug\NeuroNet.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1

Приложение однопоточное, но в будущем планирую подключить AMP (Accelerated Massive Parallelism).
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373107
sherzod_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreybs,

Пока видно следующее

По флагам - стоит дебаг режим (это значительно медленнее), отключена оптимизация /Od, включена проверка границ массивов. Видимо это просто дебаг-конфигурация, добавьте релиз-конфигурацию и в ней замеряйте скорость.
По коду - попробуйте заменить std::map на std::unordered_map, используйте префиксный ++ для итераторов.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373146
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreybs, используй Replace Condition With Polimorphysm.
Код: plaintext
1.
2.
3.
4.
class Activate {...};
class Linear : Activate {...};
class Logistic: Activate {...};
class TanHyp : Activate {...};
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373318
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonandreybs, используй Replace Condition With Polimorphysm.
Код: plaintext
1.
2.
3.
4.
class Activate {...};
class Linear : Activate {...};
class Logistic: Activate {...};
class TanHyp : Activate {...};



Обязательно. Вообще я планировал использовать "лямбды". Вот только с производительностью разбирусь...
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373344
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Я не знаю практически полезных use-case с лямбдами в С++. Всё тки
в С++ надо играть по правилам его использования.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373356
maytonЯ не знаю практически полезных use-case с лямбдами в С++. Всё тки
в С++ надо играть по правилам его использования.
Вы серьёзно, не знаете где lambdas могут быть полезны?
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373655
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
sherzod_andreybs,

Пока видно следующее

По флагам - стоит дебаг режим (это значительно медленнее), отключена оптимизация /Od, включена проверка границ массивов. Видимо это просто дебаг-конфигурация, добавьте релиз-конфигурацию и в ней замеряйте скорость.
По коду - попробуйте заменить std::map на std::unordered_map, используйте префиксный ++ для итераторов.

Поигрался с компилятором - релис-конфигурация не помогла. Прирост минорный - 5%.

/Yu"stdafx.h" /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /Fd"Release\vc110.pdb" /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Ot /Fp"Release\NeuroNet.pch"

Еще попробую немного поиграть с параметрами оптимизации, но похоже дело в коде. Кстати, как отключить проверку границ массивов?
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373688
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andreybssherzod_andreybs,

Пока видно следующее

По флагам - стоит дебаг режим (это значительно медленнее), отключена оптимизация /Od, включена проверка границ массивов. Видимо это просто дебаг-конфигурация, добавьте релиз-конфигурацию и в ней замеряйте скорость.
По коду - попробуйте заменить std::map на std::unordered_map, используйте префиксный ++ для итераторов.

Поигрался с компилятором - релис-конфигурация не помогла. Прирост минорный - 5%.

/Yu"stdafx.h" /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /Fd"Release\vc110.pdb" /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Ot /Fp"Release\NeuroNet.pch"

Еще попробую немного поиграть с параметрами оптимизации, но похоже дело в коде. Кстати, как отключить проверку границ массивов?

Так, сказал глупость... :) Настройки я сменил, а тестил старое приложение. Релис-конфигурация дала просто феерические результаты - 2,140 млн вычислений в секунду. В 28 раз быстрее дебаг-версии! Прям не ожидал, что оно на столько повлияет.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373837
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
sherzod_По коду - попробуйте заменить std::map на std::unordered_map, используйте префиксный ++ для итераторов.

Сделал. Интересное наблюдение - дебаг-версия ускорилась существенно, а релис-версия осталась такой же.
Пробовал использовать доступ к элементам unsorted_map через оператор [], но почему то возвращается null, хотя элементы в массиве есть. Так что оставил ++итератор.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373887
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
maytonandreybs, используй Replace Condition With Polimorphysm.
Код: plaintext
1.
2.
3.
4.
class Activate {...};
class Linear : Activate {...};
class Logistic: Activate {...};
class TanHyp : Activate {...};



Я попробовал простой динамический вызов функции, указатель которой хранится в каждой структуре. Производительность упала на 7%. Если динамический вызов работает медленнее switch, то нет смысла рассматривать полиморфизм и лямбды, т.к. это еще медленнее.

Переход от структур к классам нежелателен. Хотя попробовать ради эксперимента можно.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38373921
sherzod_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreybs,

Если настолько важна скорость, заинлайньте функции. Они все у вас вызываются в циклах, поэтому выигрыш будет довольно значимый.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38374032
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
sherzod_andreybs,

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

Хорошая мысль, обязательно попробую!
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38374222
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreybs,

Если в map только три элемента, не лучше ли использовать вектор вместо нее?
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38374299
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
sherzod_andreybs,

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

Безуспешно. Даже __forceinline не влияет на производительность.

Еще попробовал связанный со структурой полиморфный класс с одной функцией расчета. Быстрее, чем динамический вызов функции по указателю, но прироста в производительности не дал. Зато можно разносить код по разным функциям.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38374306
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
MasterZivandreybs,

Если в map только три элемента, не лучше ли использовать вектор вместо нее?

Для производительности может и лучше, а для логики работы - хуже, т.к. присутствует достаточно частое обращение к элементам по id и поиск будет тормозить, если использовать вектор. Но ничто не мешает одновременно использовать вектор и карту.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38374384
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Нашел простое и элегантное (на мой взгляд) решение:

Код: plaintext
1.
2.
3.
4.
5.
typedef void (*pF)(T* arg);
inline void F1(T* arg);
inline void F2(T* arg);
inline void F3(T* arg);
pF F[] = { F1, F2, F3 };



Далее обращаемся к F[0](arg), как к F1(arg) без потери производительности.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38375534
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreybsMasterZivandreybs,

Если в map только три элемента, не лучше ли использовать вектор вместо нее?

Для производительности может и лучше, а для логики работы - хуже, т.к. присутствует достаточно частое обращение к элементам по id и поиск будет тормозить, если использовать вектор. Но ничто не мешает одновременно использовать вектор и карту.


В трёх элементах? Ну ну.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38375540
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreybsandreybsпропущено...


Поигрался с компилятором - релис-конфигурация не помогла. Прирост минорный - 5%.

/Yu"stdafx.h" /GS /GL /analyze- /W3 /Gy /Zc:wchar_t /Zi /Gm- /O2 /Fd"Release\vc110.pdb" /fp:precise /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /Fa"Release\" /EHsc /nologo /Fo"Release\" /Ot /Fp"Release\NeuroNet.pch"

Еще попробую немного поиграть с параметрами оптимизации, но похоже дело в коде. Кстати, как отключить проверку границ массивов?

Так, сказал глупость... :) Настройки я сменил, а тестил старое приложение. Релис-конфигурация дала просто феерические результаты - 2,140 млн вычислений в секунду. В 28 раз быстрее дебаг-версии! Прям не ожидал, что оно на столько повлияет.

Не мудрено, Debug режим вообще ни для чего не предназначен, кроме отладки.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38375555
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreybssherzod_По коду - попробуйте заменить std::map на std::unordered_map, используйте префиксный ++ для итераторов.

Сделал. Интересное наблюдение - дебаг-версия ускорилась существенно, а релис-версия осталась такой же.
Пробовал использовать доступ к элементам unsorted_map через оператор [], но почему то возвращается null, хотя элементы в массиве есть. Так что оставил ++итератор.

Скорость debug сборки мерить вообще бессмысленно.

Так тебе теперь хватает скорости в релиз сборке?

Если нет — сори сборку с профайлером, запусти и погляди, где главный тормоз.

Только не мерий ее скорость , и лучше уменьши размерность задачи, что бы программа когда-то кончилась, потому что с профайлером все очень медленно работает.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38375611
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
andreybsНашел простое и элегантное (на мой взгляд) решение:

Код: plaintext
1.
2.
3.
4.
5.
typedef void (*pF)(T* arg);
inline void F1(T* arg);
inline void F2(T* arg);
inline void F3(T* arg);
pF F[] = { F1, F2, F3 };



Далее обращаемся к F[0](arg), как к F1(arg) без потери производительности.


Копнув глубже в производительность и подсчитав число тиков выяснил, что в приведенном выше примере inline не работает. Оно и понятно - переход ведь по указателю происходит. Поэтому если субколла не удается избежать, то лучше использовать ускоренный вызов (экономит 5% тиков в моем случае):

Код: plaintext
1.
2.
3.
4.
5.
typedef void (__fastcall* F)(T* arg);
void __fastcall F1(T* arg);
void __fastcall F1(T* arg);
void __fastcall F1(T* arg);
const static FActNeuron ActNeuron[] = { F1, F2, F3 };
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38375613
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
MasterZivandreybsпропущено...


Для производительности может и лучше, а для логики работы - хуже, т.к. присутствует достаточно частое обращение к элементам по id и поиск будет тормозить, если использовать вектор. Но ничто не мешает одновременно использовать вектор и карту.


В трёх элементах? Ну ну.

Элементов может быть чуть больше и тогда линейный поиск усложнится в разы. А вот для перебора через итератор маленького массива (до 12 элементов) разницы вообще нет. Проверил со счетчиками.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38375625
andreybs
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
MasterZivТак тебе теперь хватает скорости в релиз сборке?


Теперь хватает. Сейчас я тестирую разные способы организации структуры блока вычислений, чтобы он не проседал при разрастании логики вычислений. Потом попробую параллельные вычисления AMP. А дальше на полученном движке буду решать реальную задачу.
...
Рейтинг: 0 / 0
оптимизация производительности консольного приложения
    #38376011
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
andreybs, а профилировщик что показывает? Есть возможность подгрузить
задачу на 1-2 минуты объёмом? Маппинг std::map<int, T3*> можно попробовать
заменить на работу с указателями. Всётки мапа больше на целочисленный ID
расчитана. А если у тебя всё in-memory то можно где-то "сократить маршрут".
...
Рейтинг: 0 / 0
25 сообщений из 26, страница 1 из 2
Форумы / C++ [игнор отключен] [закрыт для гостей] / оптимизация производительности консольного приложения
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]