代码之家  ›  专栏  ›  技术社区  ›  Lodle

检查内存是否归零的最快方法

  •  4
  • Lodle  · 技术社区  · 16 年前

    我有一个程序需要检查一个文件块是否归零或有数据。这个算法运行整个文件的大小高达两个gig,需要一段时间运行。有没有更好的方法来检查它是否归零?

    平台:Linux和Windows

    bool WGTController::isBlockCompleted(wgBlock* block)
    {
        if (!block)
            return false;
    
        uint32 bufSize = (uint32)block->size;
        uint64 fileSize = UTIL::FS::UTIL_getFileSize(m_szFile);
    
        if (fileSize < (block->size + block->fileOffset))
            return false;
    
        char* buffer = new char[bufSize];
    
        FHANDLE fh=NULL;
    
        try
        {
            fh = UTIL::FS::UTIL_openFile(m_szFile, UTIL::FS::FILE_READ);
            UTIL::FS::UTIL_seekFile(fh, block->fileOffset);
            UTIL::FS::UTIL_readFile(fh, buffer, bufSize);
            UTIL::FS::UTIL_closeFile(fh);
        }
        catch (gcException &)
        {
            SAFE_DELETEA(buffer);
            UTIL::FS::UTIL_closeFile(fh);
            return false;
        }
    
        bool res = false;
    
        for (uint32 x=0; x<bufSize; x++)
        {
            if (buffer[x] != 0)
            {
                res = true;
                break;
            }
        }
    
        SAFE_DELETEA(buffer);
        return res;
    }
    
    7 回复  |  直到 16 年前
        1
  •  6
  •   jerryjvl    16 年前

    “一段时间”有多长?…我想说,尝试并行比较尽可能多的值会有帮助,也许使用一些SIMD指令一次比较超过4个字节?

    但是请记住,无论您进行比较的速度有多快,最终还是需要从文件中读取数据。如果文件不在内存中的某个缓存中,那么在磁盘带宽达到饱和之前,您可能会被限制为以100-150 MB/s的最大速率。如果您已经达到了这一点,那么您可能首先需要考虑一种避免加载文件的方法,或者只接受这样一个事实:它不会比这更快。

        2
  •  2
  •   beef2k    16 年前

    文件/块块中是否存在更可能具有非零值的位置?你只要找到 非零值(您的中断条件),所以请先查找最有可能找到它们的地方——不必是文件/块的开头。根据实际应用情况,从末尾开始或检查中间的1/3可能是有意义的。

    但是,我不建议随机跳转到不同的位置;从磁盘读取可能会变得难以置信;)…

        3
  •  0
  •   toto    16 年前

    我想看看这个函数的汇编输出。 你可以做的一些事情,将大大加快它是使用SSE指令。使用这些指令,您可以一次加载8个字节,检查所有字节是否为零,然后继续。 你也可以把它展开几次。

        4
  •  0
  •   Futurist    16 年前

    你的算法看起来不错,但你可以启发式地优化开始的地方,如果你事先知道你将得到什么类型的文件…但再次,如果它是一个特定的文件,最有可能的信息将在头(前几个字节)。

    另外,请确保块的大小不是来自调用该方法的人的1:。

    还可以查看Boost的内存映射文件功能…这可能会有所帮助,具体取决于如何计算最佳块大小->

        5
  •  0
  •   Futurist    16 年前

    我有一个“开箱即用”的答案给你,但我不确定在你的情况下实施是多么可行。

    如果你不控制倾倒过程:因为这是一个大的回收(倾倒?)在例外情况下生成的文件,为什么不在转储后立即扫描低优先级的文件(0字节),然后以某种方式标记该文件以便以后更快地识别?(或者您可以压缩它,稍后解析/扫描zip文件)

    或者,如果您控制了转储过程:(一个缓慢的过程,您无论如何都要做)为什么不在转储文件的末尾(或者返回并在其开头写入)指出转储文件是由0填充的还是有一些有效的数据(因为您编写了它,并且您知道其中包含什么)?这样,您就不必为I/O开销支付两次。

    这里的目标是通过将过程延迟到更久的时间,使读取速度更快,因为当转储发生时,不太可能有操作员等待它加载。

        6
  •  0
  •   Dolphin    16 年前

    首先,不要每次都分配一个新的缓冲区。分配一个(每个线程)并重用它。使用一个很好的大块,并进行多次读取/检查。
    其次,不要比较每个字符。对较大的整数类型进行比较。很可能您需要32位int,但根据您的操作系统/编译器的不同,使用64位甚至128位int可能会更快。使用32位int,您的比较数量将减少4倍。当然,您的意志需要担心结束条件。为此,很容易,如果要比较的缓冲区不是int大小的偶数倍,只需在进行比较之前将最后x个字节设置为0。 第三,它可能有助于编译器展开循环。在循环体中进行4或8次比较。这将有助于编译器进行一点优化,并减少退出循环的比较次数。确保缓冲区是比较类型的倍数x循环中比较的数目。 第四,使用(*pbuffer++)而不是缓冲区[i]可能更快,特别是当缓冲区很大时。

    当然,对于其中的任何一个,您都希望获得一些度量标准,并了解实际有什么帮助。

        7
  •  0
  •   fortran    16 年前

    我会告诉你一个肮脏,不便携和困难的方式,但比可以更有效…如果您处理的是稀疏的文件,那么您真的很无聊,并且想要处理您正在使用的文件系统的内部,您可以尝试添加一个新的函数,该函数将返回一个位图,指示哪些块被映射,哪些块没有映射(那些没有映射的块被归零,其余的块仍然需要手动检查)。

    是的,我知道这很疯狂,没有人愿意做这种事。