필자는 SDR 장치 (초당 1000 만개의 복잡한 샘플 (샘플은 짧은 유형 임))에서 버퍼를 고속으로 가져 오는 도구를 작성했습니다. 그러나 필자가 작성한 코드로 작성된 내용을 다시 볼 때마다 작은 덩어리가 누락되었습니다.C++의 고속 버퍼링
이 문제를 줄이기 위해 시도한 방법은 같은 크기의 두 버퍼를 사용하여 샘플을 놓치지 않기 위해 두 버퍼를 교환하는 것입니다. 청크는 내가 버퍼를 교환하고 샘플을 백 버퍼 (샘플 속도의 3 배)로 오프로드하는 과정을 거칠 때마다 사라지고 필요한 경우 디스크에 새 데이터를 쓰는 새 스레드를 호출합니다.
SDR 장치 자체는 자체 내부 버퍼 크기를 2016과 같은 이상한 것으로 알리고 실제 및 가상 샘플 배열에 대한 두 개의 포인터를 제공합니다. 분명히이 샘플 속도에서 그러한 작은 배열의 오버 헤드를 피하기 위해 크기가 더 큰 스와핑 버퍼를 구현하여 이러한 문제를 피할 수있는 희망으로 65536을 말하지만 아무 소용이 없습니다.
나는 스왑 핑 버퍼의 크기를 줄이면 누락 된 청크가 더 자주 발생하기 때문에 문제가 콜백 함수에서 발생할 가능성이 가장 높다고 지적했다.
잘못된 방식으로 가고 있습니까? 아니면 내 솔루션에 누락 된 부분이 있습니까? 아니면 제대로 작성하지 않았습니까?
나는이 표준 데이터 속도 때문에 느리기 때문에 가능한 표준 libary를 피했다. 따라서 memmove와 memcpy가 필요하다. 유일한 예외는 버퍼 포인터 스와핑 및 스레드 생성입니다. IQType가
IQType<short>* bufferA;
IQType<short>* bufferB;
:
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;
}
}
}
후방 버퍼에 기록하고 관련 t_write 다음 SDR 샘플 데이터를 언로드
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 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를 이동 시켰지만, 30 밀리언 샘플을 저장하기 위해 5 초가 걸렸습니다. memmove는이 작업을 수백 배 빠르게 수행합니다. Justy는 내가 기록하는 것 이외에 backbuffer에있는 데이터로 다른 일을 명확히하기 위해 설명합니다. 후방 버퍼는 기록 된 데이터의 마지막 3 초를 관찰하는데도 사용됩니다. 대기열과 비슷하게 처리되지만 백 버퍼의 크기까지 모든 위치와 길이를 볼 수있는 옵션이 있습니다. – Gelion