2016-10-31 3 views
3

Ich muss einige Legacy-Code optimieren und bin ziemlich neu in C++.C++ Container für Hochleistungs-FIFO

Der Code verarbeitet Netzwerkpakete in zwei Threads, wobei ein Thread Pakete zu einem FIFO [topupBuffer] und der andere Thread aus der Warteschlange liest und ihnen einen IP-Socket [writeToIPOutput] sendet. Der Legacy-Code verwendet std :: deque, um den FIFO zu implementieren.

Allerdings läuft das Programm eine Menge CPU, bis zu 50% (wo es mehr wie 5% sein muss). Laufen gprof scheint zu offenbaren std::deque ist der Schuldige. (Ich bin nicht sicher, ob ich das Profil Ergebnisse richtig bin zu interpretieren, so Hilfe ist willkommen)

excepts aus dem Profilausgang: topupBuffer Hierarchie:

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] 

und

[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 Hierarchie

[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] 

Ich denke, writeToIPOutput verbringt zu viel Zeit bei der Zuweisung. Daran kann ich arbeiten. Aber topupBuffer verbringt seine Zeit in std::deque.

Ist das die korrekte Interpretation der Profilausgabe?

Wenn ja, dann wird ein anderer Container effizienter und wenn ja, welcher?

Danke

EDIT I ​​ die Erläuterungen am Ende der Aufrufstruktur sagt:

% 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. 

So bei bufferizeTsPackets suchen, 1,15 in ihren Kindern verbracht wird, davon 0,30, + 0.30 + 0.11 = 0.71 wird in verschiedenen Deque-Methoden (push_back, size etc.) ausgegeben. Recht? Also 0,71 ist mehr als die Hälfte der Gesamtzeit (1,15) verbrachte in den Kindern (??)

+0

Haben Sie versucht, unseren geliebten Freund, ['std :: vector'] (http://en.cppreference.com/w/cpp/container/vector) zu verwenden? Für FIFO, obwohl banal, aber Sie möchten vielleicht prüfen, ['std :: queue'] (http://en.cppreference.com/w/cpp/container/queue) mit einem Vektor als zugrunde liegenden Container – WhiZTiM

+0

Ich frage mich, ob Eine ['boost :: lockfree :: queue'] (http://www.boost.org/doc/libs/1_59_0/doc/html/boost/lockfree/queue.html) würde besser funktionieren. – NathanOliver

+0

Versuchen Sie, jedes Element in der 'Deque' zu einem kurzen Vektor von Arbeitselementen zu machen. Auf diese Weise haben Sie nicht so viele Operationen auf der gemeinsamen Datenstruktur. –

Antwort

0

Eine effizientere Struktur wäre, eine ringförmige Warteschlange (Ring-Puffer) mit einem Array zu implementieren.

Da Arrays eine feste Größe haben, müssen Sie entweder das Array groß genug machen, so dass keine Daten überschritten werden; oder nur die letzten N Werte speichern, wobei N die Kapazität des Puffers ist.

Viele eingebettete Systeme verwenden Arrays, um Probleme der Speicherfragmentierung durch den dynamischen Speicherort zu reduzieren.

Wenn Ihr Array klein genug ist, kann es in den Datencache des Prozessors passen; was die Berechnung beschleunigt.

+0

Nachdem ich lange herumgespielt habe, implementierte ich ein flaches, festes C-artiges Array, das die Strukturen enthielt und in einem Schnittstelle, um es * wie eine Deque * aussehen zu lassen. Viel besser jetzt! – Danny