2015-01-07 13 views
7

Ho un progetto C++ incorporato in cui sto leggendo una serie di int32 da un dispositivo hardware, quindi li impacchetta in un array int come parte di una grande struttura di dati, quindi invio a un remoto sistema su TCP/IP. Quindi, stavo usando una semplice struttura di dati con un mucchio di cose definite e ora voglio convertirle per usare i Protocol Buffers. Quindi, stavo pensando di usare un "ripetuto int32 data" come elemento del mio proto buff. Ma voglio evitare l'uso di un ciclo come questo:Buffer del protocollo C++, invio di array intero

int hardware_data[1000]; // An array that holds the data read from the hardware 
for(int i=0; i< sizeof(hardware_data); i++) 
{ 
    proto.add_data(hardware_data[i]); 
} 

Preferirei mille volte usare un metodo efficace, come la realizzazione di buff proto solo punto alle hardware_data esistenti [] array (un metodo di copia zero) , o usando memcpy da hardware_data in proto.data.

Capisco come impostare memcpy(), ma come fa il proto buff sapere quanti elementi ci sono nell'array proto.data? Posso ancora utilizzare il proto.data_size() per ottenere il numero di elementi? Esiste un modo efficace per spostare i dati dal mio hardware letto al proto buff per l'invio? C'è un modo migliore per farlo?

Kerrik, Non ero a conoscenza dell'API zero copy. Ecco la mia definizione proto:

message hardware_data 
{ 
optional Lob      lob    = 1; 
optional int32     taskSeqNum  = 2; 
optional int32     secondsOfDay = 3; 
optional float     IQOutRateKhz = 4; 
optional float     IQBwKhz   = 5; 
optional int32     tStart   = 6; 
optional int32     tOffset   = 7; 
optional float     collectionTime = 8; 
optional int32     numSamples  = 9; 
optional int32     chunk   = 10; 
optional int32     dimSize   = 11; 
repeated int32     data   = 12 [packed=true]; 
} 

io non sono sicuro di come la copia di zero avrebbe giocato in questa definizione proto buff.

+0

Quale parte dell'API [zero copy] (https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream) non è adatta a te? –

+2

L'operatore 'sizeof' restituisce la dimensione della struttura dati in * byte *, quindi per array di 1000 elementi di' int's è probabilmente 4000 e il ciclo indicherà l'array molto oltre la sua fine effettiva, causando così un comportamento indefinito. Usa 'sizeof (hadware_data)/sizeof (hardware_data [0])' per calcolare il * numero di elementi * dell'array. – CiaPan

+0

Certo .... l'ho inserito solo come codice di esempio. Il tuo commento, se corretto, non fa nulla per rispondere alla domanda su come utilizzare il buffer del protocollo. – rbwilliams

risposta

1

Sul filo, una ripetuta int32 ripetuta è codificata come una serie di varint. Una varint è una codifica a larghezza variabile in cui i valori più piccoli occupano meno spazio. Ovviamente, questo non è il modo in cui i dati sono rappresentati nell'array, quindi incorporarlo nel messaggio zero-copy non è realmente possibile.

Infatti, attualmente stai facendo due copie e puoi eliminarne una. Invece di allocare direttamente int hardware_data[1000], prendere in considerazione l'inserimento dei dati direttamente in un google::protobuf::RepeatedField<int>. È quindi possibile fare un uso intelligente della Swap() per spostare i dati in un messaggio senza una copia:

RepeatedField<int> hardware_data; 
hardware_data.Reserve(expected_size); 
get_data_somehow(&hardware_data); 

// later 
proto.mutable_data()->Swap(&hardware_data); 

Dopo aver serializzato il messaggio, si potrebbe desiderare di Swap in aggiunta() il campo di nuovo, in modo da poter riutilizzare la memoria che era già riservata. (RepeatedField::Clear() non libera la memoria sottostante, basta contrassegnarla per riutilizzarla.)

Con tutto ciò, la serializzazione del messaggio richiederà comunque di copiare i dati come parte della codifica. Anche se la codifica è stata modificata in fixed32 ripetuto (che è effettivamente codificato come numeri interi a 32 bit sul filo), non c'è modo di convincere la libreria a utilizzare direttamente la memoria.

+0

Grazie Kenton, sembra che non ci sia modo efficiente per me di usare i proto buff. Ricorda che questa è una piattaforma integrata. Sto elaborando molti dati sullo spettro radio in tempo reale. Quindi le prestazioni sono un problema critico per me. La copia eccessiva di dati da un luogo all'altro è molto dispendiosa. Penso che questa sia una buona ragione per non usare i proto buff. – rbwilliams

+0

@rbwilliams: Sono d'accordo, la libreria protobuf C++ probabilmente fa troppa allocazione per essere utilizzabile in un ambiente embedded. Potresti guardare a protobuf-c per vedere se è meglio. In alternativa, potresti anche avere più fortuna con [Cap'n Proto] (https://capnproto.org), che è tutto sull'evitare copie. Cap'n Proto non ti permette abbastanza di "annettere" un array esterno in un messaggio al momento, ma sarebbe abbastanza facile da aggiungere e sarei felice di farlo se ne hai bisogno. (Divulgazione: sono l'autore di entrambe le librerie Protobuf C++ e Cap'n Proto.) –

Problemi correlati