Ive писал инструмент, который берет в буфер на высокой скорости с устройства SDR (10 миллионов сложных выборок в секунду (образцы короткие)). Но с кодом, который я написал, я теряю небольшие куски, когда я оглядываюсь на то, что было написано.Высокоскоростная буферизация в C++
Способ, которым я попытался решить эту проблему, заключается в использовании двух буферов одинакового размера и обмена между ними, чтобы избежать пропусков каких-либо образцов. Куски пропадают, когда я просматриваю процесс замены буферов и выгружает образцы в задний буфер (размер которого в 3 раза превышает частоту дискретизации), и при необходимости вызывает новый поток для записи новых данных на диск.
Устройство SDR само рекламирует свой собственный внутренний размер буфера как нечто странное, как 2016, и дает два указателя на реальные и мнимые массивы образцов. Очевидно, я хотел избежать накладных расходов таких небольших массивов на этой частоте дискретизации, поэтому, реализуя обменные буферы с большим размером, скажем 65536, надеюсь, я мог бы надеяться избежать таких проблем, но безуспешно.
У меня есть контакт, указывающий на проблему, скорее всего, на функцию обратного вызова, поскольку, когда я уменьшаю размер подстановочных буферов, пропавшие куски становятся более частыми.
Я иду об этом неправильно или есть что-то более очевидное, которого я не вижу в своем решении, или я что-то не написал правильно?
Я избегал стандартной библиотеки как можно больше просто потому, что она слишком медленна для такого рода скорости передачи данных, следовательно, требуется memmove и memcpy. Единственными исключениями являются обмен указателем буфера и создание потоков.
Перестановка буферы реализованы в виде:
IQType<short>* bufferA;
IQType<short>* bufferB;
IQType является:
template <class T> class IQType {
public:
T inPhaseValue;
T quadraturePhaseValue;
IQType() : inPhaseValue(0), quadraturePhaseValue(0){};
IQType(T i, T q) : inPhaseValue(i), quadraturePhaseValue(q){};
};
СДР устройство функции обратного вызова, который выгружает выборки данных SDR:
void MiricsDataSource::newSamplesCallBack(short *xi, short *xq, unsigned int firstSampleNum, int grChanged, int rfChanged, int fsChanged, unsigned int numSamples, unsigned int reset, void *cbContext) {
MiricsDataSource* mirCtx = static_cast<MiricsDataSource*>(cbContext);
for (int i = 0; i < numSamples; ++i)
{
mirCtx->bufferA[mirCtx->bufferCount] = IQType<short>(xi[i],xq[i]);
mirCtx->bufferCount++;
if(mirCtx->bufferCount == mirCtx->bufferSize-1) {
std::swap(mirCtx->bufferA,mirCtx->bufferB);
mirCtx->owner->backBuffer->write(mirCtx->bufferB,mirCtx->bufferSize);
mirCtx->bufferCount = 0;
}
}
}
BackBuffer записи и связанной с t_write функции:
void BackBuffer::write(const IQType<short>* buff, size_t bLength) {
std::thread dumpThread(&BackBuffer::t_write,this,buff,bLength);
dumpThread.detach();
}
void BackBuffer::t_write(const IQType<short>* buff, size_t bLength) {
std::lock_guard<std::mutex> lck (bufferMutex);
memmove(&backBuffer[0],(&backBuffer[0])+bLength,(sizeof(IQType<short>*)*(length-bLength)));
memcpy(&backBuffer[length-bLength],buff,(sizeof(IQType<short>*)*(bLength)));
if(dumpToFile) {
IQType<short>* toWrite = new IQType<short>[bLength];
memcpy(toWrite,buff,(sizeof(IQType<short>*)*(bLength)));
strmDmpMgr->write(toWrite,bLength);
}
}
'Я избегал стандартной библиотеки как можно больше, потому что она слишком медленна для такого рода скорости передачи данных, поэтому требуется memmove и memcpy. Я просто не покупаю ее, когда я отчетливо вижу, что стандартная библиотека просто делает memcpy/memmove, когда типы тривиальны, как в вашем случае. Если вы действительно не измерили его, пожалуйста, удалите это заявление. – Arunmu
«Я как можно больше избегал стандартной библиотеки [...], поэтому потребность в [функциях из стандартной библиотеки]« кажется немного противоречивой. – user2079303
Первоначально я использовал std :: rotate для перемещения backbuffer, но это заняло 5 секунд для хранения 30 миллионов образцов. memmove делает это в сотни раз быстрее. Justy, чтобы прояснить, я делаю другие вещи с данными в backbuffer, кроме записи. Бэкбуффер также используется для наблюдения за последние 3 секунды записанных данных. Его обрабатывают аналогично очереди, но с возможностью просмотра любой позиции и любой длины до размера буфера обмена – Gelion