c - 快速二进制解析器算法

标签 c performance parsing

我正在为二进制文件编写一个解析器。数据存储在连续的 32 位记录中。文件只需读取一次,读取完成后将其输入分析算法。

现在我正在以 1024 条记录为单位读取文件,以尽可能避免因不必要地更频繁地调用 fread 而产生的开销。在下面的示例中,我使用 oflcorrection、timetag 和 channel 作为算法的输出,并使用 bool 返回值来检查算法是否应该停止。另请注意,并非所有记录都只包含具有正值的光子。

通过这种方法,如果我使用将文件分成多个部分的算法的线程版本,我可以处理高达 0.5GBps 或 1.5GBps。我知道我的 SSD 读取速度至少可以提高 40%。我正在考虑使用 SIMD 并行解析多个记录,但我不知道如何使用条件返回子句来实现。

您是否知道任何其他方法可以让我结合分块读取和 SIMD?通常有更好的方法吗?

谢谢

附言这些记录对应于通过分束器后到达检测器的光子或指示溢出情况的特殊记录。后者是必需的,因为时间标签以皮秒分辨率存储在 uint64_t 中。

 static inline bool next_photon(FILE* filehandle, uint64_t * RecNum,
                               uint64_t StopRecord, record_buf_t *buffer,
                               uint64_t *oflcorrection, uint64_t *timetag, int *channel)
{
    pop_record:
    while (__builtin_unpredictable(buffer->head < RECORD_CHUNK)) { // still have records on buffer
        ParseHHT2_HH2(buffer->records[buffer->head], channel, timetag, oflcorrection);
        buffer->head++;
        (*RecNum)++;

        if (*RecNum >= StopRecord) { // run out of records
            return false;
        }

        if (*channel >= 0) { // found a photon
            return true;
        }
    }
    // run out of buffer
    buffer->head = 0;
    fread(buffer->records, RECORD_CHUNK, sizeof(uint32_t), filehandle);
    goto pop_record;
}

请在下面找到解析函数。请记住,我无法对文件格式做任何事情。再次感谢,Guillem。

static inline void ParseHHT2_HH2(uint32_t record, int *channel,
                                 uint64_t *timetag, uint64_t *oflcorrection)
{
    const uint64_t T2WRAPAROUND_V2 = 33554432;
    union{
        uint32_t   allbits;
        struct{ unsigned timetag  :25;
            unsigned channel  :6;
            unsigned special  :1;
        } bits;
    } T2Rec;

    T2Rec.allbits = record;

    if(T2Rec.bits.special) {
        if(T2Rec.bits.channel==0x3F) {  //an overflow record
            if(T2Rec.bits.timetag!=0) {
                *oflcorrection += T2WRAPAROUND_V2 * T2Rec.bits.timetag;
            }
            else {  // if it is zero it is an old style single overflow
                *oflcorrection += T2WRAPAROUND_V2;  //should never happen with new Firmware!
            }
            *channel = -1;
        } else if(T2Rec.bits.channel == 0) {  //sync
            *channel = 0;
        } else if(T2Rec.bits.channel<=15) {  //markers
            *channel = -2;
        }
    } else {//regular input channel
        *channel = T2Rec.bits.channel + 1;
    }
    *timetag = *oflcorrection + T2Rec.bits.timetag;
}

我想出了一个几乎没有分支的解析函数,但它没有产生任何加速。

if(T2Rec.bits.channel==0x3F) {  //an overflow record
        *oflcorrection += T2WRAPAROUND_V2 * T2Rec.bits.timetag;
    }
    *channel = (!T2Rec.bits.special) * (T2Rec.bits.channel + 1) - T2Rec.bits.special * T2Rec.bits.channel;
    *timetag = *oflcorrection + T2Rec.bits.timetag;
}

最佳答案

您正在循环访问磁盘,我认为 SIMD 不会有太大帮助,您可以使用 mmap。

检查这些答案:

When should I use mmap for file access?

Fastest file reading in C

但您也可以将 SIMD (SSE/AVX/NEON) 用于其他部分,例如在解析代码中

关于c - 快速二进制解析器算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47676197/

相关文章:

c - * 和/在 C 中的优先级

c - 有符号整型的大小范围

c++ - lib\app_error.c|49|error : expected '=' , ',' , ';' , 'asm' or '__attribute__' before 'void' Nortic Semi 例子

ruby - 在 Nokogiri CSS 选择器中指定图像宽度和/或高度的范围

c++ - 如何管理SVG文件中的超出范围的值?

javascript - 使用 jQuery 在 2 个引号之间查找文本

c - 将指针/数组从函数传递给 main()

Mysql:唯一索引=大型数据集的性能特征?

java - jvisualvm 线程 cpu 时间使用

php - php中的数组冲突