Медленно работающий код

В моем проекте есть следующая функция:

void UDPBasicApp::incrementReceiveCounter(L3Address dest) {
    char numberOfDestNode[10];
    char name[50];
    strcpy(name,L3AddressResolver().findHostWithAddress(dest)->getFullPath().c_str());
    char temp[20];
    char *last = strrchr(name, '.');
    char *realLast = last + 1;
    std::cout << "Destination is: " << realLast<<", IP is: "<<L3AddressResolver().resolve(realLast);//=====
    strcpy(temp,realLast);
    strtok(temp,"[");
    strcpy(numberOfDestNode, strtok(NULL, "]"));
    int realDestNumber = std::stoi(numberOfDestNode);
    recArray[realDestNumber]++;
    std::cout<<", Number of destination is: "<<realDestNumber<<std::endl;//=================
}

Код выполняется очень красиво и быстро, но когда эта функция вызывается, выполнение идет значительно медленнее. Этот код является частью проекта моделирования в Omnet ++, и эта функция вызывается каждый раз, когда узел отправляет сообщение другому. Итак, подумайте, если есть 1000 узлов, эта функция будет вызываться 1000 раз. Возможно, я здесь делаю что-то ненужное.


person Saad    schedule 07.03.2018    source источник
comment
Решение и блокировка - не фантастический план. В идеале вы должны начать решение; а затем, когда решение будет завершено, вы получите обратный вызов. Не могу сказать, поддерживает ли L3AddressResolver эту функцию уже; но если это так; это то, что вы хотите использовать   -  person UKMonkey    schedule 07.03.2018
comment
Это очень очевидно, но если это ваш настоящий код и вы хотите, чтобы он выполнялся быстро, можете ли вы удалить или закомментировать операторы cout? После этого вы можете избежать хотя бы части копирования строк, но вам действительно следует профилировать, прежде чем вносить дополнительные изменения.   -  person Useless    schedule 07.03.2018
comment
std::cout может быть очень медленным, в зависимости от того, на что он выводит (например, терминал). Можете ли вы сохранить результаты в памяти, чтобы распечатать их позже?   -  person Galik    schedule 07.03.2018
comment
Операторы @Useless cout предназначены только для того, чтобы убедиться, что результаты получены. Я пробовал их комментировать. '   -  person Saad    schedule 07.03.2018
comment
@ Галик да пробовал. удаление операторов cout не помогает   -  person Saad    schedule 07.03.2018
comment
Если удаление обоих операторов cout вообще не влияет на время, что-то происходит чрезвычайно медленно. В любом случае, понимание должно заключаться в том, что вам нужно измерить и научиться профилировать.   -  person Useless    schedule 07.03.2018
comment
Насколько медленный медленный, в точных цифрах? Это очень важная информация, когда вы пытаетесь разобраться в проблеме.   -  person James Z    schedule 07.03.2018


Ответы (2)


Код можно немного оптимизировать:

  • Класс L3Address имеет удобный метод operator<<, поэтому использование L3AddressResolver().resolve(realLast) не требуется ( INET API).
  • Следует избегать использования cout для ведения журнала (Руководство по OMNeT ++). EV следует использовать вместо cout.
  • Для получения индекса модуля в векторе модулей можно использовать метод getIndex() из класса cModule.

Представленный код можно переписать в следующий:

void UDPBasicApp::incrementReceiveCounter(const L3Address& dest) {       
  cModule *destHost = L3AddressResolver().findHostWithAddress(dest);
  if (destHost) {
        int realDestNumber = destHost->getIndex();
        recArray[realDestNumber]++;
        EV << "Destination is: " << destHost->getName() <<", IP is: "
           << dest << ", Number of destination is: "
           << realDestNumber << std::endl;
   }
}

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

  1. Построение симуляции в режиме выпуска.
  2. Запуск моделирования в режиме Cmdenv.
person Jerzy D.    schedule 07.03.2018
comment
toIPv4() действительно эквивалентен? Если это так, он выполняет ту же работу, что и существующий код; если нет, значит, вы нарушили код! - person Lightness Races in Orbit; 07.03.2018
comment
toIPv4() полностью эквивалентен при условии, что в сети используется IPv4. Более общее решение - напечатать только L3Address объект, потому что он operator<< проверяет тип адреса. Я улучшил свой ответ. - person Jerzy D.; 07.03.2018
comment
Есть ли причина, по которой вы не рекомендуете использовать модули статистики, поставляемые с OMNeT ++, вместо ведения журнала cout / EV? Я ожидал, что это будет намного эффективнее, чем ведение журнала cout / EV. - person Rens van der Heijden; 08.03.2018
comment
@RensvanderHeijden Код в моем ответе делает то же самое, что и код в вопросе. Я не знаю, какова интенсивность записи на консоль в исходном коде, поэтому я не могу предложить другое решение. - person Jerzy D.; 08.03.2018
comment
Просроченное спасибо. Вы ответили на вопрос и, насколько мне известно, добавили еще немного понимания омнета. Ваше здоровье - person Saad; 12.03.2018

Если вы отправляете 1000 сообщений в тот же пункт назначения, значит, вы выполняете 999 ненужных поисков имен. Для каждого из них может потребоваться обратный путь к DNS-серверу в вашей сети. Это очень неэффективно.

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

Невозможно предоставить более подробную информацию без MCVE или, по крайней мере, некоторого представления о том, что именно делает L3AddressResolver.

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

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

person Lightness Races in Orbit    schedule 07.03.2018
comment
Кто-то может возразить, что L3AddressResolver может уже делать все это, и это теоретически верно, но я думаю, что результаты OP говорят сами за себя (и, следовательно, говорят с противником). - person Lightness Races in Orbit; 07.03.2018
comment
каждый раз, когда адресат генерируется случайным образом. Это не всегда одно и то же. Я знаю, что ты имеешь в виду, но каждый раз, когда его называют - person Saad; 07.03.2018
comment
L3AddressResolver разрешает ip узла из его имени или наоборот - person Saad; 07.03.2018
comment
@Saad: L3AddressResolver разрешает ip узла по его имени или наоборот Да, я понял этот бит. Вопрос в том, как это достигается. - person Lightness Races in Orbit; 07.03.2018
comment
@Saad: каждый раз по-разному, когда вызывается Тогда мало что можно сделать. - person Lightness Races in Orbit; 07.03.2018
comment
Не уверен, что прямо означает L3AddressResolver. Но если это не POD, вы можете немного снизить скорость, передав ее через ссылку вместо значения. - person M4rc; 07.03.2018
comment
@ M4rc: Прохождение откуда? - person Lightness Races in Orbit; 07.03.2018
comment
В зависимости от того, где размещен объект и его время жизни, как параметр. - person M4rc; 07.03.2018
comment
@ M4rc: Это не параметр в показанном нам коде. - person Lightness Races in Orbit; 07.03.2018
comment
@LightnessRacesinOrbit Я должен был быть более понятным - параметр dest типа L3AddressResolver. - person M4rc; 07.03.2018
comment
@ M4rc: Ах, вы имеете в виду параметр dest типа L3Address. Тогда да, я согласен, в некоторой степени - по сравнению с затратами на разрешение имен, это, вероятно, будет очень мало, но, похоже, нет причин передавать это по значению. - person Lightness Races in Orbit; 07.03.2018
comment
Вопрос был не очень ясным, но L3AddressResolver в основном преобразует IP-адреса в узлы OMNeT ++ (которые являются смоделированными экземплярами реальных машин, например, серверов или узлов в одноранговой сети). Этот шаг необходим только потому, что серверная часть моделирования не работает с IP-адресами. - person Rens van der Heijden; 08.03.2018