Commit 5daf1563 authored by Pavel Vainerman's avatar Pavel Vainerman Committed by Pavel Vainerman

(unet): processing optimization (crc cache)

parent b1bf6785
...@@ -26,12 +26,15 @@ ...@@ -26,12 +26,15 @@
static bool HostIsBigEndian = false; static bool HostIsBigEndian = false;
#define LE_TO_H(x) {} #define LE_TO_H(x) {}
#define LE32_TO_H(x) {} #define LE32_TO_H(x) {}
#define LE16_TO_H(x) {}
#elif INTPTR_MAX == INT64_MAX #elif INTPTR_MAX == INT64_MAX
#define LE_TO_H(x) x = le64toh(x) #define LE_TO_H(x) x = le64toh(x)
#define LE32_TO_H(x) x = le32toh(x) #define LE32_TO_H(x) x = le32toh(x)
#define LE16_TO_H(x) x = le16toh(x)
#elif INTPTR_MAX == INT32_MAX #elif INTPTR_MAX == INT32_MAX
#define LE_TO_H(x) x = le32toh(x) #define LE_TO_H(x) x = le32toh(x)
#define LE32_TO_H(x) x = le32toh(x) #define LE32_TO_H(x) x = le32toh(x)
#define LE16_TO_H(x) x = le16toh(x)
#else #else
#error UNET(LE_TO_H): Unknown byte order or size of pointer #error UNET(LE_TO_H): Unknown byte order or size of pointer
#endif #endif
...@@ -40,12 +43,15 @@ static bool HostIsBigEndian = false; ...@@ -40,12 +43,15 @@ static bool HostIsBigEndian = false;
static bool HostIsBigEndian = true; static bool HostIsBigEndian = true;
#define BE_TO_H(x) {} #define BE_TO_H(x) {}
#define BE32_TO_H(x) {} #define BE32_TO_H(x) {}
#define BE16_TO_H(x) {}
#elif INTPTR_MAX == INT64_MAX #elif INTPTR_MAX == INT64_MAX
#define BE_TO_H(x) x = be64toh(x) #define BE_TO_H(x) x = be64toh(x)
#define BE32_TO_H(x) x = be32toh(x) #define BE32_TO_H(x) x = be32toh(x)
#define BE16_TO_H(x) x = be16toh(x)
#elif INTPTR_MAX == INT32_MAX #elif INTPTR_MAX == INT32_MAX
#define BE_TO_H(x) x = be32toh(x) #define BE_TO_H(x) x = be32toh(x)
#define BE32_TO_H(x) x = be32toh(x) #define BE32_TO_H(x) x = be32toh(x)
#define BE16_TO_H(x) x = be16toh(x)
#else #else
#error UNET(BE_TO_H): Unknown byte order or size of pointer #error UNET(BE_TO_H): Unknown byte order or size of pointer
#endif #endif
...@@ -139,7 +145,9 @@ namespace uniset ...@@ -139,7 +145,9 @@ namespace uniset
<< " procID=" << p.procID << " procID=" << p.procID
<< " dcount=" << p.dcount << " dcount=" << p.dcount
<< " acount=" << p.acount << " acount=" << p.acount
<< " pnum=" << p.num; << " pnum=" << p.num
<< " dcrc=" << p.dcrc
<< " acrc=" << p.acrc;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPHeader* p ) std::ostream& UniSetUDP::operator<<( std::ostream& os, UniSetUDP::UDPHeader* p )
...@@ -256,9 +264,6 @@ namespace uniset ...@@ -256,9 +264,6 @@ namespace uniset
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
long UDPMessage::getDataID() const noexcept long UDPMessage::getDataID() const noexcept
{ {
// в качестве идентификатора берётся ID первого датчика в данных
// приоритет имеет аналоговые датчики
if( header.acount > 0 ) if( header.acount > 0 )
return a_dat[0].id; return a_dat[0].id;
...@@ -287,6 +292,8 @@ namespace uniset ...@@ -287,6 +292,8 @@ namespace uniset
BE_TO_H(header.nodeID); BE_TO_H(header.nodeID);
BE_TO_H(header.dcount); BE_TO_H(header.dcount);
BE_TO_H(header.acount); BE_TO_H(header.acount);
BE16_TO_H(header.dcrc);
BE16_TO_H(header.acrc);
} }
else if( !be_order && HostIsBigEndian ) else if( !be_order && HostIsBigEndian )
{ {
...@@ -296,6 +303,8 @@ namespace uniset ...@@ -296,6 +303,8 @@ namespace uniset
LE_TO_H(header.nodeID); LE_TO_H(header.nodeID);
LE_TO_H(header.dcount); LE_TO_H(header.dcount);
LE_TO_H(header.acount); LE_TO_H(header.acount);
LE16_TO_H(header.dcrc);
LE16_TO_H(header.acrc);
} }
// set host byte order // set host byte order
...@@ -339,15 +348,25 @@ namespace uniset ...@@ -339,15 +348,25 @@ namespace uniset
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
uint16_t UDPMessage::getDataCRC() const noexcept void UDPMessage::updatePacketCrc() noexcept
{ {
uint16_t crc[3]; header.dcrc = calcDcrc();
crc[0] = makeCRC( (unsigned char*)(a_dat), sizeof(a_dat) ); header.acrc = calcAcrc();
crc[1] = makeCRC( (unsigned char*)(d_id), sizeof(d_id) ); }
crc[2] = makeCRC( (unsigned char*)(d_dat), sizeof(d_dat) ); // -----------------------------------------------------------------------------
uint16_t UDPMessage::calcDcrc() const noexcept
{
uint16_t crc[2];
crc[0] = makeCRC( (unsigned char*)(d_id), sizeof(d_id) );
crc[1] = makeCRC( (unsigned char*)(d_dat), sizeof(d_dat) );
return makeCRC( (unsigned char*)(&crc), sizeof(crc) ); return makeCRC( (unsigned char*)(&crc), sizeof(crc) );
} }
// -----------------------------------------------------------------------------
uint16_t UDPMessage::calcAcrc() const noexcept
{
return makeCRC( (unsigned char*)(&a_dat), sizeof(a_dat) );
}
// -----------------------------------------------------------------------------
UDPHeader::UDPHeader() noexcept UDPHeader::UDPHeader() noexcept
: magic(UNETUDP_MAGICNUM) : magic(UNETUDP_MAGICNUM)
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
...@@ -362,6 +381,8 @@ namespace uniset ...@@ -362,6 +381,8 @@ namespace uniset
, procID(0) , procID(0)
, dcount(0) , dcount(0)
, acount(0) , acount(0)
, dcrc(0)
, acrc(0)
{} {}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
......
...@@ -50,11 +50,13 @@ namespace uniset ...@@ -50,11 +50,13 @@ namespace uniset
UDPHeader() noexcept; UDPHeader() noexcept;
uint32_t magic; uint32_t magic;
uint8_t _be_order; // 1 - BE byte order, 0 - LE byte order uint8_t _be_order; // 1 - BE byte order, 0 - LE byte order
size_t num; size_t num; // порядковый номер сообщения
int64_t nodeID; int64_t nodeID;
int64_t procID; int64_t procID;
size_t dcount; /*!< количество булевых величин */ size_t dcount; /*!< количество булевых величин */
size_t acount; /*!< количество аналоговых величин */ size_t acount; /*!< количество аналоговых величин */
uint16_t dcrc; /*!< crc по дискретным датчикам */
uint16_t acrc; /*!< crc по аналоговым датчикам */
} __attribute__((packed)); } __attribute__((packed));
std::ostream& operator<<( std::ostream& os, UDPHeader& p ); std::ostream& operator<<( std::ostream& os, UDPHeader& p );
...@@ -134,7 +136,9 @@ namespace uniset ...@@ -134,7 +136,9 @@ namespace uniset
return header.acount; return header.acount;
} }
uint16_t getDataCRC() const noexcept; uint16_t calcDcrc() const noexcept;
uint16_t calcAcrc() const noexcept;
void updatePacketCrc() noexcept;
UDPHeader header; UDPHeader header;
UDPAData a_dat[MaxACount]; /*!< аналоговые величины */ UDPAData a_dat[MaxACount]; /*!< аналоговые величины */
......
...@@ -79,6 +79,7 @@ UNetExchange::UNetExchange(uniset::ObjectId objId, uniset::ObjectId shmId, const ...@@ -79,6 +79,7 @@ UNetExchange::UNetExchange(uniset::ObjectId objId, uniset::ObjectId shmId, const
int checkConnectionPause = conf->getArgPInt("--" + prefix + "-checkconnection-pause", it.getProp("checkConnectionPause"), 10000); int checkConnectionPause = conf->getArgPInt("--" + prefix + "-checkconnection-pause", it.getProp("checkConnectionPause"), 10000);
int initpause = conf->getArgPInt("--" + prefix + "-initpause", it.getProp("initpause"), 5000); int initpause = conf->getArgPInt("--" + prefix + "-initpause", it.getProp("initpause"), 5000);
int recvBufferSize = conf->getArgPInt("--" + prefix + "-recv-buffer-size", it.getProp("recvBufferSize"), 100); int recvBufferSize = conf->getArgPInt("--" + prefix + "-recv-buffer-size", it.getProp("recvBufferSize"), 100);
bool recvIgnoreCrc = conf->getArgPInt("--" + prefix + "-recv-ignore-crc", it.getProp("recvIgnoreCRC"), 0);
int recvMaxReceiveCount = conf->getArgPInt("--" + prefix + "-recv-max-at-time", it.getProp("recvMaxAtTime"), 5); int recvMaxReceiveCount = conf->getArgPInt("--" + prefix + "-recv-max-at-time", it.getProp("recvMaxAtTime"), 5);
const string unet_transport = conf->getArg2Param("--" + prefix + "-transport", it.getProp("transport"), "broadcast"); const string unet_transport = conf->getArg2Param("--" + prefix + "-transport", it.getProp("transport"), "broadcast");
...@@ -133,6 +134,7 @@ UNetExchange::UNetExchange(uniset::ObjectId objId, uniset::ObjectId shmId, const ...@@ -133,6 +134,7 @@ UNetExchange::UNetExchange(uniset::ObjectId objId, uniset::ObjectId shmId, const
r.r1->setMaxDifferens(maxDiff); r.r1->setMaxDifferens(maxDiff);
r.r1->setBufferSize(recvBufferSize); r.r1->setBufferSize(recvBufferSize);
r.r1->setMaxReceiveAtTime(recvMaxReceiveCount); r.r1->setMaxReceiveAtTime(recvMaxReceiveCount);
r.r1->setIgnoreCRC(recvIgnoreCrc);
} }
if( r.r2 ) if( r.r2 )
...@@ -147,6 +149,7 @@ UNetExchange::UNetExchange(uniset::ObjectId objId, uniset::ObjectId shmId, const ...@@ -147,6 +149,7 @@ UNetExchange::UNetExchange(uniset::ObjectId objId, uniset::ObjectId shmId, const
r.r2->setMaxDifferens(maxDiff); r.r2->setMaxDifferens(maxDiff);
r.r2->setBufferSize(recvBufferSize); r.r2->setBufferSize(recvBufferSize);
r.r2->setMaxReceiveAtTime(recvMaxReceiveCount); r.r2->setMaxReceiveAtTime(recvMaxReceiveCount);
r.r2->setIgnoreCRC(recvIgnoreCrc);
} }
} }
...@@ -610,6 +613,7 @@ void UNetExchange::help_print( int argc, const char* argv[] ) noexcept ...@@ -610,6 +613,7 @@ void UNetExchange::help_print( int argc, const char* argv[] ) noexcept
cout << "--prefix-nosender [0,1] - Отключить посылку." << endl; cout << "--prefix-nosender [0,1] - Отключить посылку." << endl;
cout << "--prefix-recv-buffer-size sz - Размер циклического буфера для приёма сообщений. По умолчанию: 100" << endl; cout << "--prefix-recv-buffer-size sz - Размер циклического буфера для приёма сообщений. По умолчанию: 100" << endl;
cout << "--prefix-recv-max-at-time num - Максимальное количество сообщений вычитываемых из сети за один раз. По умолчанию: 5" << endl; cout << "--prefix-recv-max-at-time num - Максимальное количество сообщений вычитываемых из сети за один раз. По умолчанию: 5" << endl;
cout << "--prefix-recv-ignore-crc [0,1] - Отключить оптимизацию по проверке crc, обновлять данные в SM всегда. По умолчанию: 0" << endl;
cout << "--prefix-sm-ready-timeout msec - Время ожидание я готовности SM к работе. По умолчанию 120000" << endl; cout << "--prefix-sm-ready-timeout msec - Время ожидание я готовности SM к работе. По умолчанию 120000" << endl;
cout << "--prefix-filter-field name - Название фильтрующего поля при формировании списка датчиков посылаемых данным узлом" << endl; cout << "--prefix-filter-field name - Название фильтрующего поля при формировании списка датчиков посылаемых данным узлом" << endl;
cout << "--prefix-filter-value name - Значение фильтрующего поля при формировании списка датчиков посылаемых данным узлом" << endl; cout << "--prefix-filter-value name - Значение фильтрующего поля при формировании списка датчиков посылаемых данным узлом" << endl;
......
...@@ -56,29 +56,36 @@ namespace uniset ...@@ -56,29 +56,36 @@ namespace uniset
* КЭШ * КЭШ
* === * ===
* Для оптимизации работы с SM, т.к. в пакетах приходят только пары [id,value] сделан кэш итераторов. * Для оптимизации работы с SM, т.к. в пакетах приходят только пары [id,value] сделан кэш итераторов.
* Идея проста: сделан вектор размером с количество принимаемых данных. В векторе хранятся итераторы (и всё что необходимо). * Идея проста: сделан вектор размером с количеством принимаемых данных. В векторе хранятся итераторы (и всё что необходимо).
* Порядковый номер данных в пакете является индексом в кэше. * Порядковый номер данных в пакете является индексом в кэше.
* Для защиты от изменения последовательности внутри пакета, в кэше хранится ID сохраняемого датчика, и если он не совпадёт с тем, * Для защиты от изменения последовательности внутри пакета, в кэше хранится ID сохраняемого датчика, и если он не совпадёт с тем,
* ID который пришёл в пакете - элемент кэша обновляется. * ID который пришёл в пакете - элемент кэша обновляется.
* Если количество пришедших данных не совпадают с размером кэша.. кэш обновляется. * Если количество пришедших данных не совпадают с размером кэша - кэш обновляется.
* *
* КЭШ (ДОПОЛНЕНИЕ) * КЭШ (ДОПОЛНЕНИЕ)
* === * ===
* Т.к. в общем случае, данные могут быть разбиты не несколько (много) пакетов, то для каждого из них выделен свой кэш и создан отдельный * Т.к. в общем случае, данные могут быть разбиты на несколько (много) пакетов, то для каждого из них выделен свой кэш и создан отдельный
* map, ключом в котором является идентификатор данных (см. UDPMessage::getDataID()). * map, ключом в котором является идентификатор данных (см. UDPMessage::getDataID()).
* Кэш в map добавляется когда приходит пакет с новым UDPMessage::getDataID() и в дальнейшим используется для этого пакета. * Кэш в map добавляется тогда, когда приходит пакет с новым UDPMessage::getDataID() и в дальнейшим он используется для этого пакета.
* В текущей реализации размер map не контролируется (завязан на UDPMessage::getDataID()) и рассчитан на статичность пакетов, * В текущей реализации размер map не контролируется (завязан на UDPMessage::getDataID()) и рассчитан на статичность пакетов,
* т.е. на то что UNetSender не будет с течением времени менять структуру отправляемых пакетов. * т.е. на то что UNetSender не будет с течением времени менять количество отправляемых пакетов
* (работать будет, просто в map останутся лежать записи для неиспользуемых пакетов)
*
* ОПТИМИЗАЦИЯ
* ===
* В кэше так же хранится crc последних принятых данных. Если crc совпадает с тем, что пришло в пакете, то обработки не происходит.
* crc хранится отдельно для дискретных и отдельно для аналоговых датчиков.
* Эту оптимизацию можно отключить параметром --prefix-recv-ignore-crc или recvIgnoreCRC="1" в конф. файле.
* *
* Обработка сбоев в номере пакетов * Обработка сбоев в номере пакетов
* ========================================================================= * =========================================================================
* Если в какой-то момент расстояние между rnum и wnum превышает maxDifferens пакетов * Если в какой-то момент расстояние между rnum и wnum превышает maxDifferens пакетов
* то считается, что произошёл сбой или узел который посылал пакеты перезагрузился * то считается, что произошёл сбой или узел который посылал пакеты - перезагрузился
* Идёт попытка обработать все текущие пакеты (до первой дырки), а дальше происходит * Идёт попытка обработать все текущие пакеты (до первой дырки), а дальше происходит
* реинициализация и обработка продолжается с нового номера. * реинициализация и обработка продолжается с нового номера.
* *
* ========================================================================= * =========================================================================
* ОПТИМИЗАЦИЯ N1: см. UNetSender.h. Если номер последнего принятого пакета не менялся.. не обрабатываем. * ОПТИМИЗАЦИЯ N1: см. UNetSender.h. Если номер последнего принятого пакета не менялся, пакет не обрабатываем.
* *
* Создание соединения (открытие сокета) * Создание соединения (открытие сокета)
* ====================================== * ======================================
...@@ -130,6 +137,7 @@ namespace uniset ...@@ -130,6 +137,7 @@ namespace uniset
void setInitPause( timeout_t msec ) noexcept; void setInitPause( timeout_t msec ) noexcept;
void setBufferSize( size_t sz ) noexcept; void setBufferSize( size_t sz ) noexcept;
void setMaxReceiveAtTime( size_t sz ) noexcept; void setMaxReceiveAtTime( size_t sz ) noexcept;
void setIgnoreCRC( bool set ) noexcept;
void setRespondID( uniset::ObjectId id, bool invert = false ) noexcept; void setRespondID( uniset::ObjectId id, bool invert = false ) noexcept;
void setLostPacketsID( uniset::ObjectId id ) noexcept; void setLostPacketsID( uniset::ObjectId id ) noexcept;
...@@ -179,6 +187,7 @@ namespace uniset ...@@ -179,6 +187,7 @@ namespace uniset
void updateEvent( ev::periodic& watcher, int revents ) noexcept; void updateEvent( ev::periodic& watcher, int revents ) noexcept;
void checkConnectionEvent( ev::periodic& watcher, int revents ) noexcept; void checkConnectionEvent( ev::periodic& watcher, int revents ) noexcept;
void statisticsEvent( ev::periodic& watcher, int revents ) noexcept; void statisticsEvent( ev::periodic& watcher, int revents ) noexcept;
void onForceUpdate( ev::async& watcher, int revents ) noexcept;
void initEvent( ev::timer& watcher, int revents ) noexcept; void initEvent( ev::timer& watcher, int revents ) noexcept;
virtual void evprepare( const ev::loop_ref& eloop ) noexcept override; virtual void evprepare( const ev::loop_ref& eloop ) noexcept override;
virtual void evfinish(const ev::loop_ref& eloop ) noexcept override; virtual void evfinish(const ev::loop_ref& eloop ) noexcept override;
...@@ -205,6 +214,7 @@ namespace uniset ...@@ -205,6 +214,7 @@ namespace uniset
ev::periodic evStatistic; ev::periodic evStatistic;
ev::periodic evUpdate; ev::periodic evUpdate;
ev::timer evInitPause; ev::timer evInitPause;
ev::async evForceUpdate;
// счётчики для подсчёта статистики // счётчики для подсчёта статистики
size_t recvCount = { 0 }; size_t recvCount = { 0 };
...@@ -277,16 +287,25 @@ namespace uniset ...@@ -277,16 +287,25 @@ namespace uniset
CacheItem(): CacheItem():
id(uniset::DefaultObjectId) {} id(uniset::DefaultObjectId) {}
}; };
typedef std::vector<CacheItem> CacheVec; typedef std::vector<CacheItem> CacheVec;
struct CacheInfo
{
uint16_t crc;
CacheVec items;
CacheInfo(): crc(0) {}
};
// ключом является UDPMessage::getDataID() // ключом является UDPMessage::getDataID()
typedef std::unordered_map<long, CacheVec> CacheMap; typedef std::unordered_map<long, CacheInfo> CacheMap;
CacheMap d_icache_map; /*!< кэш итераторов для булевых */ CacheMap d_icache_map; /*!< кэш итераторов для булевых */
CacheMap a_icache_map; /*!< кэш итераторов для аналоговых */ CacheMap a_icache_map; /*!< кэш итераторов для аналоговых */
size_t cacheMissed; // количество промахов
bool ignoreCRC = { false }; /*!< отключение проверки crc */
CacheVec* getDCache( UniSetUDP::UDPMessage* pack ) noexcept; CacheInfo* getDCache( UniSetUDP::UDPMessage* pack ) noexcept;
CacheVec* getACache( UniSetUDP::UDPMessage* pack ) noexcept; CacheInfo* getACache( UniSetUDP::UDPMessage* pack ) noexcept;
}; };
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
} // end of namespace uniset } // end of namespace uniset
......
...@@ -43,8 +43,7 @@ namespace uniset ...@@ -43,8 +43,7 @@ namespace uniset
packsendpause(5), packsendpause(5),
packsendpauseFactor(1), packsendpauseFactor(1),
activated(false), activated(false),
packetnum(1), packetnum(0),
lastcrc(0),
maxAData(maxACount), maxAData(maxACount),
maxDData(maxDCount) maxDData(maxDCount)
{ {
...@@ -280,31 +279,21 @@ namespace uniset ...@@ -280,31 +279,21 @@ namespace uniset
unetinfo << "************* execute FINISH **********" << endl; unetinfo << "************* execute FINISH **********" << endl;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// #define UNETUDP_DISABLE_OPTIMIZATION_N1
void UNetSender::real_send( PackMessage& mypack ) noexcept void UNetSender::real_send( PackMessage& mypack ) noexcept
{ {
try try
{ {
uniset::uniset_rwmutex_rlock l(mypack.mut); packetnum++;
#ifdef UNETUDP_DISABLE_OPTIMIZATION_N1
mypack.msg.num = packetnum++;
#else
uint16_t crc = mypack.msg.getDataCRC();
if( crc != lastcrc )
{
mypack.msg.header.num = packetnum++;
lastcrc = crc;
}
#endif
// при переходе через ноль (когда счётчик перевалит через UniSetUDP::MaxPacketNum.. // при переходе через ноль (когда счётчик перевалит через UniSetUDP::MaxPacketNum..
// делаем номер пакета "1" // делаем номер пакета "1"
if( packetnum == 0 ) if( packetnum == 0 )
packetnum = 1; packetnum = 1;
uniset::uniset_rwmutex_rlock l(mypack.mut);
mypack.msg.header.num = packetnum;
mypack.msg.updatePacketCrc();
if( !transport->isReadyForSend(writeTimeout) ) if( !transport->isReadyForSend(writeTimeout) )
return; return;
...@@ -500,7 +489,6 @@ namespace uniset ...@@ -500,7 +489,6 @@ namespace uniset
<< UniSetUDP::MaxACount << endl << flush; << UniSetUDP::MaxACount << endl << flush;
std::terminate(); std::terminate();
return false;
} }
} }
...@@ -512,7 +500,6 @@ namespace uniset ...@@ -512,7 +500,6 @@ namespace uniset
unetcrit << myname unetcrit << myname
<< "(readItem): Sensor (" << p.id << ")" << sname << " ALREADY ADDED!! ABORT!" << endl; << "(readItem): Sensor (" << p.id << ")" << sname << " ALREADY ADDED!! ABORT!" << endl;
std::terminate(); std::terminate();
return false;
} }
items.emplace(p.id, std::move(p)); items.emplace(p.id, std::move(p));
...@@ -551,7 +538,6 @@ namespace uniset ...@@ -551,7 +538,6 @@ namespace uniset
s << setw(15) << std::right << transport->toString() s << setw(15) << std::right << transport->toString()
<< " lastpacknum=" << packetnum << " lastpacknum=" << packetnum
<< " lastcrc=" << setw(6) << lastcrc
<< " items=" << items.size() << " maxAData=" << getADataSize() << " maxDData=" << getDDataSize() << " items=" << items.size() << " maxAData=" << getADataSize() << " maxDData=" << getDDataSize()
<< " packsendpause[factor=" << packsendpauseFactor << "]=" << packsendpause << " packsendpause[factor=" << packsendpauseFactor << "]=" << packsendpause
<< " sendpause=" << sendpause << " sendpause=" << sendpause
...@@ -568,7 +554,10 @@ namespace uniset ...@@ -568,7 +554,10 @@ namespace uniset
{ {
//uniset_rwmutex_rlock l(p->mut); //uniset_rwmutex_rlock l(p->mut);
s << " \t\t[" << (n++) << "]=" << sizeof(pack.msg) << " bytes" s << " \t\t[" << (n++) << "]=" << sizeof(pack.msg) << " bytes"
<< " ( numA=" << setw(5) << pack.msg.asize() << " numD=" << setw(5) << pack.msg.dsize() << ")" << " (dataID=" << setw(5) << pack.msg.getDataID()
<< " numA=" << setw(5) << pack.msg.asize()
<< " numD=" << setw(5) << pack.msg.dsize()
<< ")"
<< endl; << endl;
} }
} }
......
...@@ -48,12 +48,6 @@ namespace uniset ...@@ -48,12 +48,6 @@ namespace uniset
* В initItem() каждому UItem в dlist кроме pack_ind присваивается еще и номер пакета pack_num, который гарантировано соответствует * В initItem() каждому UItem в dlist кроме pack_ind присваивается еще и номер пакета pack_num, который гарантировано соответствует
* существующему пакету, поэтому в дальнейшем при использовании pack_num в качестве ключа в mypacks мы не проверяем пакет на существование. * существующему пакету, поэтому в дальнейшем при использовании pack_num в качестве ключа в mypacks мы не проверяем пакет на существование.
* *
* ОПТИМИЗАЦИЯ N1: Для оптимизации обработки посылаемых пакетов (на стороне UNetSender) сделана следующая логика:
* Номер очередного посылаемого пакета меняется (увеличивается) только, если изменились данные с момента
последней посылки. Для этого по данным каждый раз производится расчёт UNetUDP::makeCRC() и сравнивается с последним.
На стороне UNetReceiver пакеты с повторными номерами (т.е. уже обработанные) - откидываются.
*
*
* Создание соединения * Создание соединения
* ====================================== * ======================================
* Попытка создать соединение производиться сразу в конструкторе, если это не получается, * Попытка создать соединение производиться сразу в конструкторе, если это не получается,
...@@ -203,13 +197,13 @@ namespace uniset ...@@ -203,13 +197,13 @@ namespace uniset
typedef std::unordered_map<sendfactor_t, std::vector<PackMessage>> Packs; typedef std::unordered_map<sendfactor_t, std::vector<PackMessage>> Packs;
// mypacks заполняется в начале и дальше с ним происходит только чтение // mypacks заполняется в начале и дальше с ним происходит только чтение
// (меняются данные внутри пакетов, но не меняется само количество пакетов)
// поэтому mutex-ом его не защищаем // поэтому mutex-ом его не защищаем
Packs mypacks; Packs mypacks;
std::unordered_map<sendfactor_t, size_t> packs_anum; std::unordered_map<sendfactor_t, size_t> packs_anum;
std::unordered_map<sendfactor_t, size_t> packs_dnum; std::unordered_map<sendfactor_t, size_t> packs_dnum;
UItemMap items; UItemMap items;
size_t packetnum = { 1 }; /*!< номер очередного посылаемого пакета */ size_t packetnum = { 1 }; /*!< номер очередного посылаемого пакета */
uint16_t lastcrc = { 0 };
size_t maxAData = { UniSetUDP::MaxACount }; size_t maxAData = { UniSetUDP::MaxACount };
size_t maxDData = { UniSetUDP::MaxDCount }; size_t maxDData = { UniSetUDP::MaxDCount };
......
...@@ -56,9 +56,9 @@ void InitTest() ...@@ -56,9 +56,9 @@ void InitTest()
} }
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// pnum - минималный номер ожидаемого пакета ( 0 - любой пришедщий ) // pnum - минималный номер ожидаемого пакета (0 - последний пришедщий)
// ncycle - сколько пакетов разрешено "пропустить" прежде чем дождёмся нужного. (чтобы не ждать бесконечно) // ncycle - сколько пакетов разрешено "пропустить" прежде чем дождёмся нужного. (чтобы не ждать бесконечно)
static UniSetUDP::UDPMessage receive( unsigned int pnum = 0, timeout_t tout = 2000, int ncycle = 20 ) static UniSetUDP::UDPMessage receive( unsigned int pnum = 0, timeout_t tout = 2000, int ncycle = 30 )
{ {
UniSetUDP::UDPMessage pack; UniSetUDP::UDPMessage pack;
...@@ -69,16 +69,18 @@ static UniSetUDP::UDPMessage receive( unsigned int pnum = 0, timeout_t tout = 20 ...@@ -69,16 +69,18 @@ static UniSetUDP::UDPMessage receive( unsigned int pnum = 0, timeout_t tout = 20
size_t ret = udp_r->receiveBytes(&pack, sizeof(pack) ); size_t ret = udp_r->receiveBytes(&pack, sizeof(pack) );
if( ret <= 0 || pnum == 0 || ( pnum > 0 && pack.header.num >= pnum ) ) // -V560 if( ret <= 0 )
break;
pack.ntoh();
if( pnum > 0 && pack.header.num >= pnum ) // -V560
break; break;
REQUIRE( pack.header.magic == UniSetUDP::UNETUDP_MAGICNUM ); REQUIRE( pack.header.magic == UniSetUDP::UNETUDP_MAGICNUM );
ncycle--; ncycle--;
} }
// if( pnum > 0 && pack.num < pnum )
// return UniSetUDP::UDPMessage(); // empty message
return pack; return pack;
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
...@@ -89,6 +91,7 @@ void send( UniSetUDP::UDPMessage& pack, int tout = 2000 ) ...@@ -89,6 +91,7 @@ void send( UniSetUDP::UDPMessage& pack, int tout = 2000 )
pack.header.nodeID = s_nodeID; pack.header.nodeID = s_nodeID;
pack.header.procID = s_procID; pack.header.procID = s_procID;
pack.header.num = s_numpack++; pack.header.num = s_numpack++;
pack.updatePacketCrc();
size_t ret = udp_s->sendTo(&pack, sizeof(pack), s_addr); size_t ret = udp_s->sendTo(&pack, sizeof(pack), s_addr);
REQUIRE( ret == sizeof(pack) ); REQUIRE( ret == sizeof(pack) );
...@@ -197,9 +200,10 @@ TEST_CASE("[UNetUDP]: check sender", "[unetudp][udp][sender]") ...@@ -197,9 +200,10 @@ TEST_CASE("[UNetUDP]: check sender", "[unetudp][udp][sender]")
REQUIRE( p.dValue(0) == true ); REQUIRE( p.dValue(0) == true );
REQUIRE( p.dValue(1) == false ); REQUIRE( p.dValue(1) == false );
// т.к. данные в SM не менялись, то должен придти пакет с тем же номером что и был. // т.к. данные в SM не менялись, то должен придти пакет с теми же crc что и были
UniSetUDP::UDPMessage p2 = receive(); UniSetUDP::UDPMessage p2 = receive();
REQUIRE( p2.header.num == p.header.num ); REQUIRE( p2.header.dcrc == p.header.dcrc );
REQUIRE( p2.header.acrc == p.header.acrc );
} }
SECTION("Test: change AI data..") SECTION("Test: change AI data..")
...@@ -453,7 +457,6 @@ TEST_CASE("[UNetUDP]: check undefined value", "[unetudp][udp][sender]") ...@@ -453,7 +457,6 @@ TEST_CASE("[UNetUDP]: check undefined value", "[unetudp][udp][sender]")
msleep(600); msleep(600);
UniSetUDP::UDPMessage pack = receive( pack0.header.num + 1, 2000, 40 ); UniSetUDP::UDPMessage pack = receive( pack0.header.num + 1, 2000, 40 );
REQUIRE( pack.header.num != 0 ); REQUIRE( pack.header.num != 0 );
REQUIRE( pack.asize() == 4 ); REQUIRE( pack.asize() == 4 );
REQUIRE( pack.dsize() == 2 ); REQUIRE( pack.dsize() == 2 );
...@@ -464,7 +467,7 @@ TEST_CASE("[UNetUDP]: check undefined value", "[unetudp][udp][sender]") ...@@ -464,7 +467,7 @@ TEST_CASE("[UNetUDP]: check undefined value", "[unetudp][udp][sender]")
si.node = uniset_conf()->getLocalNode(); si.node = uniset_conf()->getLocalNode();
ui->setUndefinedState(si, true, 6000 /* TestProc */ ); ui->setUndefinedState(si, true, 6000 /* TestProc */ );
msleep(600); msleep(600);
pack = receive(pack.header.num + 1); pack = receive();
REQUIRE( pack.header.num != 0 ); REQUIRE( pack.header.num != 0 );
REQUIRE( pack.asize() == 4 ); REQUIRE( pack.asize() == 4 );
...@@ -473,7 +476,7 @@ TEST_CASE("[UNetUDP]: check undefined value", "[unetudp][udp][sender]") ...@@ -473,7 +476,7 @@ TEST_CASE("[UNetUDP]: check undefined value", "[unetudp][udp][sender]")
ui->setUndefinedState(si, false, 6000 /* TestProc */ ); ui->setUndefinedState(si, false, 6000 /* TestProc */ );
msleep(600); msleep(600);
pack = receive(pack.header.num + 1); pack = receive(pack0.header.num + 1);
REQUIRE( pack.header.num != 0 ); REQUIRE( pack.header.num != 0 );
REQUIRE( pack.asize() == 4 ); REQUIRE( pack.asize() == 4 );
......
...@@ -100,7 +100,12 @@ static UniSetUDP::UDPMessage mreceive( unsigned int pnum = 0, timeout_t tout = 2 ...@@ -100,7 +100,12 @@ static UniSetUDP::UDPMessage mreceive( unsigned int pnum = 0, timeout_t tout = 2
size_t ret = udp_r->receive(&pack, sizeof(pack) ); size_t ret = udp_r->receive(&pack, sizeof(pack) );
if( ret == 0 || pnum == 0 || ( pnum > 0 && pack.header.num >= pnum ) ) // -V560 if( ret <= 0 )
break;
pack.ntoh();
if( pnum > 0 && pack.header.num >= pnum ) // -V560
break; break;
REQUIRE( pack.header.magic == UniSetUDP::UNETUDP_MAGICNUM ); REQUIRE( pack.header.magic == UniSetUDP::UNETUDP_MAGICNUM );
...@@ -120,6 +125,7 @@ void msend( UniSetUDP::UDPMessage& pack, int tout = 2000 ) ...@@ -120,6 +125,7 @@ void msend( UniSetUDP::UDPMessage& pack, int tout = 2000 )
pack.header.nodeID = s_nodeID; pack.header.nodeID = s_nodeID;
pack.header.procID = s_procID; pack.header.procID = s_procID;
pack.header.num = s_numpack++; pack.header.num = s_numpack++;
pack.updatePacketCrc();
size_t ret = udp_s->send(&pack, sizeof(pack)); size_t ret = udp_s->send(&pack, sizeof(pack));
REQUIRE( ret == sizeof(pack) ); REQUIRE( ret == sizeof(pack) );
...@@ -144,9 +150,10 @@ TEST_CASE("[UNetUDP]: check multicast sender", "[unetudp][multicast][sender]") ...@@ -144,9 +150,10 @@ TEST_CASE("[UNetUDP]: check multicast sender", "[unetudp][multicast][sender]")
REQUIRE( pack.dValue(0) == 1 ); REQUIRE( pack.dValue(0) == 1 );
REQUIRE( pack.dValue(1) == 0 ); REQUIRE( pack.dValue(1) == 0 );
// т.к. данные в SM не менялись, то должен придти пакет с тем же номером что и был.. // т.к. данные в SM не менялись, то должен придти пакет с теми же crc
UniSetUDP::UDPMessage pack2 = mreceive(); UniSetUDP::UDPMessage pack2 = mreceive();
REQUIRE( pack2.header.num == pack.header.num ); REQUIRE( pack2.header.dcrc == pack.header.dcrc );
REQUIRE( pack2.header.acrc == pack.header.acrc );
} }
SECTION("Test: change AI data...") SECTION("Test: change AI data...")
......
...@@ -10,5 +10,5 @@ cd - ...@@ -10,5 +10,5 @@ cd -
./uniset2-start.sh -f ./tests-with-sm $* -- --confile unetudp-test-configure.xml --e-startup-pause 10 \ ./uniset2-start.sh -f ./tests-with-sm $* -- --confile unetudp-test-configure.xml --e-startup-pause 10 \
--unet-name UNetExchange --unet-filter-field unet --unet-filter-value 1 --unet-maxdifferense 5 \ --unet-name UNetExchange --unet-filter-field unet --unet-filter-value 1 --unet-maxdifferense 5 \
--unet-recv-timeout 1000 --unet-sendpause 500 --unet-update-strategy evloop --unet-recv-timeout 1000 --unet-sendpause 500 --unet-update-strategy evloop
#--unet-log-add-levels any #--unet-log-add-levels any
...@@ -70,7 +70,7 @@ int main(int argc, char* argv[]) ...@@ -70,7 +70,7 @@ int main(int argc, char* argv[])
int verb = 0; int verb = 0;
std::string addr = ""; std::string addr = "";
int port = 0; int port = 0;
int usecpause = 2000000; int msecpause = 200;
timeout_t tout = UniSetTimer::WaitUpTime; timeout_t tout = UniSetTimer::WaitUpTime;
int procID = 1; int procID = 1;
int nodeID = 1; int nodeID = 1;
...@@ -143,7 +143,7 @@ int main(int argc, char* argv[]) ...@@ -143,7 +143,7 @@ int main(int argc, char* argv[])
break; break;
case 'x': case 'x':
usecpause = atoi(optarg) * 1000; msecpause = atoi(optarg);
break; break;
case 'y': case 'y':
...@@ -234,8 +234,7 @@ int main(int argc, char* argv[]) ...@@ -234,8 +234,7 @@ int main(int argc, char* argv[])
else else
cout << tout; cout << tout;
cout << " msecpause=" << usecpause / 1000 cout << " msecpause=" << msecpause << endl;
<< endl;
} }
...@@ -468,7 +467,7 @@ int main(int argc, char* argv[]) ...@@ -468,7 +467,7 @@ int main(int argc, char* argv[])
break; break;
} }
std::this_thread::sleep_for(std::chrono::microseconds(usecpause)); std::this_thread::sleep_for(std::chrono::milliseconds(msecpause));
} }
} }
break; break;
......
...@@ -67,7 +67,7 @@ int main(int argc, char* argv[]) ...@@ -67,7 +67,7 @@ int main(int argc, char* argv[])
int verb = 0; int verb = 0;
std::string addr = ""; std::string addr = "";
int port = 0; int port = 0;
int usecpause = 200000; int msecpause = 200;
timeout_t tout = UniSetTimer::WaitUpTime; timeout_t tout = UniSetTimer::WaitUpTime;
bool broadcast = true; bool broadcast = true;
int procID = 1; int procID = 1;
...@@ -134,7 +134,7 @@ int main(int argc, char* argv[]) ...@@ -134,7 +134,7 @@ int main(int argc, char* argv[])
break; break;
case 'x': case 'x':
usecpause = atoi(optarg) * 1000; msecpause = atoi(optarg);
break; break;
case 'y': case 'y':
...@@ -211,8 +211,7 @@ int main(int argc, char* argv[]) ...@@ -211,8 +211,7 @@ int main(int argc, char* argv[])
else else
cout << tout; cout << tout;
cout << " msecpause=" << usecpause / 1000 cout << " msecpause=" << msecpause << endl;
<< endl;
} }
...@@ -357,6 +356,8 @@ int main(int argc, char* argv[]) ...@@ -357,6 +356,8 @@ int main(int argc, char* argv[])
mypack.addDData(i, i); mypack.addDData(i, i);
} }
// mypack.updatePacketCrc();
Poco::Net::SocketAddress sa(s_host, port); Poco::Net::SocketAddress sa(s_host, port);
udp->connect(sa); udp->connect(sa);
...@@ -405,7 +406,7 @@ int main(int argc, char* argv[]) ...@@ -405,7 +406,7 @@ int main(int argc, char* argv[])
break; break;
} }
std::this_thread::sleep_for(std::chrono::microseconds(usecpause)); std::this_thread::sleep_for(std::chrono::milliseconds(msecpause));
} }
} }
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment