7

我试图了解为什么我构建的 grep 比系统附带的要慢得多,并试图找出系统附带的 grep 使用了哪些编译器选项。

操作系统版本:CentOS release 5.3 (Final) 系统上的 grep:

  版本:grep (GNU grep) 2.5.1
  大小:88896 字节
  ldd 输出:
 libpcre.so.0 => /lib64/libpcre.so.0 (0x0000003991800000)
 libc.so.6 => /lib64/libc.so.6 (0x0000003985a00000)
 /lib64/ld-linux-x86-64.so.2 (0x0000003984a00000)

我建立的grep:

  版本:2.5.1
  大小:256437 字节
  ldd 输出:
 libpcre.so.0 => /lib64/libpcre.so.0 (0x0000003991800000)
 libc.so.6 => /lib64/libc.so.6 (0x0000003985a00000)
 /lib64/ld-linux-x86-64.so.2 (0x0000003984a00000)

在大型列表文本文件上运行正则表达式搜索时,系统 grep(330 毫秒)的性能比我构建的 grep(22430 毫秒)快得多。

以下是我用来计时的命令..

% 时间 src/grep ".*asa.*" large_list.txt > /dev/null
真正的 0m22.430s
用户 0m22.291s
系统 0m0.080s

或者

% 时间 bin/grep ".*asa.*" large_list.txt > /dev/null
实际0m0.331s
用户 0m0.236s
系统 0m0.081s

系统 grep 显然正在使用一些优化选项,这些选项会产生巨大的性能差异。

一些机构可以帮助我构建系统 grep 的哪些选项?

这是我构建时其中一个源文件的编译选项..
gcc -DLIBDIR=\"/usr/local/lib\" -DHAVE_CONFIG_H -I. -I.. -I.. -I. -I../intl -g -O2 -MT xstrtol.o -MD -MP -MF .deps/xstrtol.Tpo -c -o xstrtol.o xstrtol.c

./configure 的输出:

检查与 BSD 兼容的安装... /usr/bin/install -c
检查构建环境是否健全......是的
检查线程安全的 mkdir -p... /bin/mkdir -p
检查 gawk... gawk
检查 make 是否设置 $(MAKE)... 是
检查构建系统类型... x86_64-unknown-linux-gnu
检查主机系统类型... x86_64-unknown-linux-gnu
检查 gawk ...(缓存) gawk
检查 gcc ... gcc
检查 C 编译器默认输出文件名... a.out
检查 C 编译器是否工作......是的
检查我们是否在交叉编译...否
检查可执行文件的后缀...
检查目标文件的后缀... o
检查我们是否正在使用 GNU C 编译器...是的
检查 gcc 是否接受 -g... 是
检查 gcc 选项以接受 ISO C89... 不需要
检查 make 使用的包含样式... GNU
检查 gcc 的依赖样式... gcc3
检查与 BSD 兼容的安装... /usr/bin/install -c
检查ranlib...ranlib
检查 getconf... getconf
检查 CFLAGS 值以请求大文件支持...
检查 LDFLAGS 值以请求大文件支持...
检查 LIBS 值以请求大文件支持...
检查 _FILE_OFFSET_BITS... 否
检查 _LARGEFILE_SOURCE... 否
检查 _LARGE_FILES... 否
检查函数原型...是的
检查如何运行 C 预处理器... gcc -E
检查处理长行的 grep 和 -e... /bin/grep
检查 egrep... /bin/grep -E
检查 ANSI C 头文件...是的
检查 sys/types.h... 是
检查 sys/stat.h... 是的
检查stdlib.h ...是的
检查 string.h... 是的
检查内存.h ...是的
检查strings.h ...是的
检查 inttypes.h ... 是的
检查stdint.h ...是的
检查 unistd.h ...是的
检查 string.h...(缓存)是
检查 size_t... 是的
检查 ssize_t... 是的
检查符合 ANSI C 的 const... 是
检查 inttypes.h ... 是的
检查无符号长长...是的
检查 ANSI C 头文件...(缓存)是
检查 string.h...(缓存)是
检查stdlib.h ...(缓存)是
检查 sys/param.h 可用性...是的
检查 sys/param.h 是否存在...是的
检查 sys/param.h... 是的
检查 memory.h...(缓存)是
检查 unistd.h...(缓存)是
检查 libintl.h 的可用性...是的
检查 libintl.h 的存在...是的
检查 libintl.h... 是的
检查 wctype.h 的可用性...是的
检查 wctype.h 的存在...是的
检查 wctype.h... 是的
检查 wchar.h 的可用性...是的
检查 wchar.h 的存在...是的
检查 wchar.h... 是的
检查定义 DIR 的 dirent.h ... 是
检查包含 opendir 的库...不需要
检查 stat 文件模式宏是否损坏...否
检查工作 alloca.h... 是的
检查分配...是的
检查 closedir 是否返回 void... 否
检查stdlib.h ...(缓存)是
检查 unistd.h...(缓存)是
检查getpagesize ...是的
检查工作的mmap ...是的
检查 btowc ......是的
检查 isascii ......是的
检查 iswctype... 是的
检查 mbrlen... 是的
检查 memmove ...是的
检查设置模式...否
检查strerror ...是的
检查 wcrtomb ......是的
检查 wcscoll... 是的
检查 wctype... 是的
检查 mbrtowc 和 mbstate_t 是否正确声明...是
检查stdlib.h ...(缓存)是
检查 mbstate_t... 是的
检查 memchr... 是的
检查 stpcpy ...是的
检查strtoul ...是的
检查 atexit... 是的
检查 fnmatch... 是的
检查stdlib.h ...(缓存)是
检查是否将 strtoumax 定义为宏...否
检查 strtoumax ......是的
检查 strtoul 是否被声明...是的
检查 strtoull 是否被声明...是的
检查 -lcposix 中的 strerror ...否
检查内联...内联
检查 off_t... 是的
检查我们是否使用 GNU C Library 2.1 或更新版本...是的
检查 argz.h 可用性...是的
检查 argz.h 的存在...是的
检查argz.h ...是的
检查limits.h可用性...是的
检查limits.h存在...是的
检查limits.h ...是的
检查 locale.h 可用性...是的
检查 locale.h 存在...是的
检查 locale.h ...是的
检查 nl_types.h 可用性...是的
检查 nl_types.h 存在...是
检查 nl_types.h... 是
检查 malloc.h 的可用性...是的
检查 malloc.h 的存在...是的
检查 malloc.h... 是的
检查 stddef.h 可用性...是的
检查 stddef.h 存在...是的
检查stddef.h ...是的
检查stdlib.h ...(缓存)是
检查 string.h...(缓存)是
检查 unistd.h...(缓存)是
检查 sys/param.h...(缓存)是
检查 feof_unlocked... 是的
检查 fgets_unlocked... 是的
检查getcwd ...是的
检查getegid ...是的
检查geteuid ...是的
检查 getgid... 是的
检查getuid ...是的
检查 mempcpy ......是的
检查 munmap... 是的
检查putenv ...是的
检查 setenv... 是的
检查 setlocale... 是的
检查 stpcpy...(缓存)是
检查 strchr ...是的
检查 strcasecmp... 是的
检查 strdup ...是的
检查 strtoul ...(缓存)是
检查 tsearch... 是的
检查 __argz_count... 是
检查 __argz_stringify... 是
检查 __argz_next... 是
检查 iconv... 是的
检查 iconv 声明...
         extern size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
检查 nl_langinfo 和 CODESET... 是
检查 LC_MESSAGES... 是
检查是否请求 NLS... 是
检查是否请求了包含的 gettext... 否
检查 libintl.h...(缓存)是
检查 libc 中的 GNU gettext ...是的
检查 dcgettext... 是的
检查 msgfmt... /usr/bin/msgfmt
检查 gmsgfmt... /usr/bin/msgfmt
检查 xgettext... /usr/bin/xgettext
检查野牛...野牛
检查野牛的版本... 2.3,好的
检查要安装的目录... af be bg ca cs da de el eo es et eu fi fr ga gl he hr hu id it ja ko ky lt nb nl pl pt pt_BR ro ru rw sk sl sr sv tr uk vi zh_TW
检查 dos 文件约定...否
检查主机系统类型...(缓存)x86_64-unknown-linux-gnu
检查主机系统类型...(缓存)x86_64-unknown-linux-gnu
检查 DJGPP 环境...否
检查环境变量分隔符...:
检查工作 re_compile_pattern... 是
检查 getopt_long... 是的
配置:警告:未使用包含的 lib/regex.c
检查是否声明了 strerror_r... 是
检查 strerror_r... 是的
检查 strerror_r 是否返回 char *... 否
检查 strerror...(缓存)是
检查 strerror_r...(缓存)是
检查 vprintf... 是的
检查 doprnt... 不
检查 ANSI C 头文件...(缓存)是
检查工作的malloc ...是的
检查工作 realloc... 是的
检查 -lpcre 中的 pcre_exec ... 是
配置:创建 ./config.status
config.status:创建 Makefile
config.status:创建 lib/Makefile
config.status:创建 lib/posix/Makefile
config.status:创建 src/Makefile
config.status:创建测试/Makefile
config.status:创建 po/Makefile.in
config.status:创建 intl/Makefile
config.status: WARNING: intl/Makefile.in 似乎忽略了 --datarootdir 设置
config.status:创建文档/Makefile
config.status: 创建 m4/Makefile
config.status:创建 vms/Makefile
config.status:创建引导程序/Makefile
config.status:创建 config.h
config.status:config.h 不变
config.status:执行 depfiles 命令
config.status:执行 default-1 命令
config.status: 创建 po/POTFILES
config.status: 创建 po/Makefile
config.status:执行 stamp -h 命令

谢谢,库马尔

4

5 回答 5

10

你为什么不直接获取 CentOS 的 grep 二进制文件的 SRPM 并将它们的编译选项与你的比较?我猜这比让整个 StackOverflow 社区在黑暗中盲目地四处寻找要有效得多。

编辑:您是否使用多字节编码的语言环境?(注意:如果你不知道这意味着什么,那么答案可能是“是”,因为 UTF-8 多年来一直是大多数 Linux 发行版的默认值,而且确实 RedHat(以及因此 CentOS)是第一个进行开关)。

在这种情况下,GNU grep速度慢。这不仅适用于 GNU grep,而且适用于几乎所有进行某种文本处理的 GNU 工具。FSF 拒绝接受任何补丁来提高多字节性能,除非这些补丁被证明不会减慢固定宽度编码的速度。然而,由于任何提高多字节编码性能的补丁都必须至少在某处包含一些if语句,因此实际上不可能编写一个补丁至少不会减慢固定宽度编码的速度,至少会降低该if语句的开销。因此,GNU 工具的 UTF-8 性能继续下降,直到时间结束。

无论如何,大多数 Linux 发行商都不会对FSF 的想法嗤之以鼻,并且无论如何都会修补 GNU grep Fedora Rawhide SRPM包含一个名为 的补丁,grep-2.5.3-egf-speedup.patch它将 GNU grep 的 UTF-8 性能提高了几个数量级。(由于这个补丁已经是 2005 年的,我假设它也用于 CentOS。)这个补丁也用于 Mac OSX、Debian、Ubuntu ......,几乎没有人使用 GNU 分发的 GNU grep。多字节编码中的文本处理永远不会像固定宽度编码中那样快,但它至少应该具有可比性,而不是慢 50 倍(或者甚至像某些人报告的那样慢 1500 倍)。

还有另一个名为 的补丁dfa-optional,它使 grep 简单地使用 GNU libc 的正则表达式引擎而不是它自己的引擎,这不仅在处理 UTF-8 时要快得多,而且 bug 也少得多

export LC_ALL=POSIX因此,您可能希望使用set重新运行基准测试。如果这样可以解决您的问题,您需要应用上述两个补丁之一。

这两个 RedHat 错误报告中还提供了更多信息:

故事的寓意:尽管普遍认为,Linux 发行商确实知道他们在做什么,至少有时是这样。不要猜测他们。

于 2009-12-24T00:22:59.367 回答
4

-O2你用标志编译。你为什么不使用-03国旗。有关 gcc 可用的优化选项的说明,请参见此处

使用英特尔的 ICC 编译器也有助于提高性能,但这实际上取决于应用程序。此外,它不是免费的。

编辑,我刚刚在您的编译行上看到了 -g 标志。删除它,因为它正在打开调试内容,这可能会导致非常严重的性能损失

于 2009-12-23T22:27:04.747 回答
1

除了 -O 选项之外,另一个需要注意的是,看起来您正在使用调试符号“-g”进行构建。

调试通常会增加二进制文件的大小并且会降低所述二进制文件的性能,我认为 grep 非常稳定,您实际上并不需要调试符号。

于 2009-12-23T22:37:51.517 回答
1

您使用的是什么版本的 GCC?IIRC,GCC 4 进行了重大重新设计,使一些优化代码失效了一段时间。

于 2009-12-24T05:35:45.547 回答
0

由于性能差距如此之大,这可能是算法/代码的差异,而不仅仅是编译器优化级别的差异。是什么让你怀疑编译器?

于 2009-12-23T22:31:04.393 回答