如何优化c ++二进制文件读取?

时间:2015-02-12 18:01:29

标签: c++ file optimization input

我有一个复杂的解释器从(有时)多个文件(确切的细节超出范围)读取命令,但它需要多次迭代这些多个文件(一些可能是GB是大小,防止好缓冲)。

我希望从文件中提高每个命令的读取速度。

我已经使用RDTSC(程序计数器)寄存器对代码进行微观基准测试,以了解大约80%的时间用于从文件中读取。

这就是事情:生成输入文件的程序比在我的小解释器中读取文件快得多。即,而不是输出文件我可以(理论上)只是将数据生成器链接到解释器并跳过文件,但这不应该更快,对吗?

我做错了什么?或者假设写入比从文件读取快2倍到3倍(至少)?

我考虑了mmap,但http://lemire.me/blog/archives/2012/06/26/which-is-fastest-read-fread-ifstream-or-mmap/上的一些结果似乎表明它并不比ifstream快。或者在这种情况下会帮助mmap吗?

细节:

我(到目前为止)尝试添加一个缓冲区,调整参数,删除ifstream缓冲区(在我的测试用例中将其减慢了6倍),我目前在搜索后不知所措。

代码的重要部分如下。它执行以下操作:

  1. 如果数据保留在缓冲区中,则将表单缓冲区复制到memblock(然后使用它)
  2. 如果数据没有留在缓冲区中,请检查文件中剩余的数据量,如果超过缓冲区的大小,则复制缓冲区大小的块
  3. 如果小于文件

    //if data in buffer
    if(leftInBuffer[activefile] > 0)
    {
        //cout <<bufferloc[activefile] <<"\n";
        memcpy(memblock,(buffer[activefile])+bufferloc[activefile],16);
        bufferloc[activefile]+=16;
        leftInBuffer[activefile]-=16;
    }
    else //buffers blank
    {
        //read in block
    
        long blockleft =  (cfilemax -cfileplace) / 16 ;
        int read=0;
    
    /* slow block starts here */
    
        if(blockleft >= MAXBUFELEMENTS)
        {
            currentFile->read((char *)(&(buffer[activefile][0])),16*MAXBUFELEMENTS);
            leftInBuffer[activefile] = 16*MAXBUFELEMENTS;
            bufferloc[activefile]=0;
            read =16*MAXBUFELEMENTS;
        }
        else //read in part of the block
        {
            currentFile->read((char *)(&(buffer[activefile][0])),16*(blockleft));
            leftInBuffer[activefile] = 16*blockleft;
            bufferloc[activefile]=0;
            read =16*blockleft;
        }
    
     /* slow block ends here */
    
        memcpy(memblock,(buffer[activefile])+bufferloc[activefile],16);
        bufferloc[activefile]+=16;
        leftInBuffer[activefile]-=16;
    }
    
  4. 编辑:这是在mac,osx 10.9.5,带有SSD的i7

    解决方案:

    如下所示,mmap能够将速度提高约10倍。

    (对于搜索此内容的其他人) 特别开放:

    uint8_t * openMMap(string name, long & size)
    {
    int m_fd;
    struct stat statbuf;
    uint8_t * m_ptr_begin;
    
    if ((m_fd = open(name.c_str(), O_RDONLY)) < 0)
    {
        perror("can't open file for reading");
    }
    
    if (fstat(m_fd, &statbuf) < 0)
    {
        perror("fstat in openMMap failed");
    }
    
    if ((m_ptr_begin = (uint8_t *)mmap(0, statbuf.st_size, PROT_READ, MAP_SHARED,  m_fd, 0)) == MAP_FAILED)
    {
        perror("mmap in openMMap failed");
    }
    
    uint8_t * m_ptr = m_ptr_begin;
    size = statbuf.st_size;
    
    return m_ptr;
    
    }
    

    阅读:

        uint8_t *  mmfile = openMMap("my_file", length);        
    
        uint32_t * memblockmm;
        memblockmm = (uint32_t *)mmfile; //cast file to uint32 array
        uint32_t data = memblockmm[0]; //take int
        mmfile +=4; //increment by 4 as I read a 32 bit entry and each entry in mmfile is 8 bits.
    

2 个答案:

答案 0 :(得分:2)

这应该是一个评论,但我没有50个发表评论的声誉。

MAXBUFELEMENTS的价值是多少?根据我的经验,许多较小的读取速度远远低于较大尺寸的读取速度。我建议尽可能读取整个文件,有些文件可能是GB,但即使一次读取100MB也会比读取1 MB 100次更好。

如果这还不够好,你可以尝试的下一件事就是压缩(zlib)输入文件(由于大小可能必须将它们分成块),并在内存中解压缩它们。此方法通常比读取未压缩文件更快。

答案 1 :(得分:0)

作为@Tony Jiang said,尝试使用缓冲区大小来查看是否有帮助。

尝试使用mmap查看是否有帮助。

我认为currentFilestd::ifstream?使用iostreams会产生一些开销(例如,istream会自行缓冲,为您正在做的事情添加额外的图层;虽然我不希望开销很大,但您可以直接使用open(2)read(2)进行测试。

您应该能够通过dtruss -e运行代码,以验证read系统调用需要多长时间。如果这些占用了大部分时间,那么您将达到操作系统和硬件限制,因此您可以通过管道,mmap,或调整缓冲区大小来解决这个问题。如果这些花费的时间少于预期,那么请在应用程序逻辑中查找问题(每次迭代都需要不必要的工作等)。