2016-10-31 4 views
3

Мне нужно оптимизировать некоторый унаследованный код и довольно новичок в C++.Контейнер C++ для высокой производительности FIFO

Код выполняет сетевую обработку пакетов в двух потоках, один поток передает пакеты в FIFO [topupBuffer], а другой поток считывает из очереди и отправляет их через IP-порт [writeToIPOutput]. Унаследованный код использует std :: deque для реализации FIFO.

Однако при запуске программы используется много CPU, до 50% (там, где это должно быть больше похоже на 5%). Похоже, что запуск gprof обнаруживает, что виновником является std::deque. (Я не уверен, что я правильно интерпретировать результаты профиля, поэтому помощь приветствуется)

Excepts с выхода профиля: topupBuffer иерархии:

index % time self children called  name 
       0.65 2.51  1/1   DvIPFilePlayback::topupBufferThreadMethod(void*) [2] 
[1]  60.5 0.65 2.51  1   DvIPFilePlayback::topupBuffer() [1] 
       0.27 1.15 4025575/4025575  DvIPPlaybackBC::bufferizeTsPackets(TPlaybackBuffer&, int&, int&) [5] 
       0.03 0.56 4026668/4026668  std::deque<TTsPacket, std::allocator<TTsPacket> >::push_back(TTsPacket const&) [6] 
       0.03 0.15 4046539/5749754  std::deque<TPlaybackBuffer, std::allocator<TPlaybackBuffer> >::size() const [17] 

и

[5]  27.2 0.27 1.15 4025575   DvIPPlaybackBC::bufferizeTsPackets(TPlaybackBuffer&, int&, int&) [5] 
       0.04 0.30 4031674/4031674  std::deque<TTsPacket, std::allocator<TTsPacket> >::pop_front() [11] 
       0.03 0.30 8058004/8058004  std::deque<TTsPacket, std::allocator<TTsPacket> >::size() const [12] 
       0.01 0.19 576183/576183  DvPlaybackBC::insertToPlaybackBuffer(TPlaybackBuffer const&) [22] 
       0.04 0.11 4029401/4029401  std::deque<TTsPacket, std::allocator<TTsPacket> >::front() [25] 

writeToIPOutput Иерархия

[3]  36.8 0.92 1.00  1   DvIPPlaybackBC::writeToIPOutput() [3] 
       0.31 0.00 1129444/1129444  TPlaybackBuffer::operator=(TPlaybackBuffer const&) [13] 
       0.01 0.18 579235/1155128  std::deque<TPlaybackBuffer, std::allocator<TPlaybackBuffer> >::push_back(TPlaybackBuffer const&) [8] 
       0.03 0.10 1135318/1135318  std::deque<TPlaybackBuffer, std::allocator<TPlaybackBuffer> >::pop_front() [27] 

Я думаю, writeToIPOutput тратит слишком много времени на назначение. Я могу поработать над этим. Но topupBuffer тратит время в std::deque.

Это правильная интерпретация выхода профиля?

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

Спасибо

EDIT I ​​ пояснительные примечания в конце дерева вызовов говорит:

% time This is the percentage of the `total' time that was spent 
     in this function and its children. Note that due to 
     different viewpoints, functions excluded by options, etc, 
     these numbers will NOT add up to 100%. 

self This is the total amount of time spent in this function. 

children This is the total amount of time propagated into this 
     function by its children. 

Так, глядя на bufferizeTsPackets, 1,15 тратится на своих детей, из которых 0,30 + 0,30 + 0,11 = 0,71 тратится на различные методы deque (push_back, размер и т. Д.). Правильно? Таким образом, 0,71 составляет более половины общего времени (1,15), потраченного на детей (??)

+0

Вы пытались использовать нашего любимого друга, ['std :: vector'] (http://en.cppreference.com/w/cpp/container/vector)? Для FIFO, хотя и обыденный, но вы можете рассмотреть ['std :: queue'] (http://en.cppreference.com/w/cpp/container/queue) с вектором в качестве базового контейнера – WhiZTiM

+0

Интересно, ['boost :: lockfree :: queue'] (http://www.boost.org/doc/libs/1_59_0/doc/html/boost/lockfree/queue.html) будет работать лучше. – NathanOliver

+0

Попробуйте сделать каждый элемент в 'deque' коротким вектором рабочих элементов, таким образом, у вас не будет столько операций над общей структурой данных. –

ответ

0

Более эффективной структурой будет реализация круговой очереди (кольцевого буфера) с использованием массива.

Поскольку массивы имеют фиксированный размер, вам необходимо либо сделать массив достаточно большим, чтобы не было переполнения данных; или сохранить только последние значения N, где N - емкость буфера.

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

Если ваш массив достаточно мал, он может поместиться в кэш данных процессора; что ускоряет вычисление.

+0

После долгой работы я реализовал плоский массив C-стиля с фиксированным размером, содержащий структуры и выполненный в интерфейс, чтобы он * выглядел * как deque. Теперь гораздо лучше! – Danny

Смежные вопросы