Cygwin / MinGW中的Git difftool可笑得很慢

时间:2015-12-01 19:28:12

标签: git cygwin mingw benchmarking git-difftool

我注意到git difftool非常慢。每次diff调用之间会出现大约1..2秒的延迟。

为了对它进行基准测试,我编写了一个自定义difftool命令:

#!/bin/sh
echo $0 $1 $2

并将Git配置为在~/.gitconfig

中使用此工具
[diff]
    tool = mydiff
[difftool "mydiff"]
    prompt = false
    cmd = "~/mydiff \"$LOCAL\" \"$REMOTE\""

我在Git上测试了它:

$ git clone https://github.com/git/git.git
$ cd git
$ git rev-parse HEAD
1bc8feaa7cc752fe3b902ccf83ae9332e40921db
$ git diff head~10 --stat --name-only | wc -l
23

当我使用git difftool计算259b5e6d33时,结果非常缓慢:

$ time git difftool 259b5
mydiff /dev/null Documentation/RelNotes/2.6.3.txt
...
mydiff /tmp/mY2T6l_upload-pack.c upload-pack.c

real    0m10.381s
user    0m1.997s
sys     0m6.667s

通过尝试更简单的脚本,它会更快:

$ time git diff --name-only --stat 259b5 | xargs -n1 -I{} sh -c 'git show 259b5:{} > {}.tmp && ~/mydiff {} {}.tmp'
mydiff Documentation/RelNotes/2.6.3.txt Documentation/RelNotes/2.6.3.txt.tmp
mydiff upload-pack.c upload-pack.c.tmp

real    0m1.149s
user    0m0.472s
sys     0m0.821s

我错过了什么?

这是我得到的结果

| Cygwin | Debian | Ubuntu | Method   |
| ------ | ------ | ------ | -------- |
| 10.381 |  2.620 | 0.580  | difftool |
|  1.149 |  0.567 | 0.210  | custom   |

对于Cygwin结果,我测量了git-difftool花费的2.8秒和git-difftool--helper花费的7.5秒。后者长98线。我不明白为什么这么慢。

3 个答案:

答案 0 :(得分:2)

使用on the msysgit GitHub找到的一些技术,我已经缩小了一点。

对于diff 中的每个文件,git-difftool--helper重新运行以下内部命令:

12:44:46.941239 git.c:351               trace: built-in: git 'config' 'diff.tool'
12:44:47.359239 git.c:351               trace: built-in: git 'config' 'difftool.bc.cmd'
12:44:47.933239 git.c:351               trace: built-in: git 'config' '--bool' 'mergetool.prompt'
12:44:48.797239 git.c:351               trace: built-in: git 'config' '--bool' 'difftool.prompt'
12:44:49.696239 git.c:351               trace: built-in: git 'config' 'difftool.bc.cmd'
12:44:50.135239 git.c:351               trace: built-in: git 'config' 'difftool.bc.path'
12:44:50.422239 git.c:351               trace: built-in: git 'config' 'mergetool.bc.path'
12:44:51.060239 git.c:351               trace: built-in: git 'config' 'difftool.bc.cmd'
12:44:51.452239 git.c:351               trace: built-in: git 'config' 'difftool.bc.cmd'

请注意,在这种特殊情况下,执行这些操作大约需要4.5秒。在我的日志中,这是一个非常一致的模式。

另请注意,其中一些是重复的 - git config difftool.bc.cmd被称为4次!

现在,可能的补救措施:

  • 通过将所有与差异相关的部分移到我的.gitconfig文件的顶部,我将这些命令的执行时间减半 。认真。它仍然很明显,但现在大约2秒而不是4.5。
  • 确保Program Files下的Git文件夹和您的用户个人资料(.gitconfig生活在哪里)都被排除在实时病毒扫描之外。
  • 从根本上说,Git需要更高效地解析和获取配置值。理想情况下,它会缓存这些而不是每次在循环中从配置重新请求(和重新分析...)。甚至可能为整个命令执行缓存。

答案 1 :(得分:1)

使用Git 2.13(2017年第2季度),

git difftool应该稍快一点 请commit d12a8cf查看Jeff Hostetler (jeffhostetler)(2017年4月14日) Junio C Hamano -- gitster --于2017年4月24日commit 8868ba1合并)

  

unpack-trees:在结帐时避免重复的ODB查找

(ODB:对象数据库)

  

当两个目录引用相同的OID时,教traverse_trees_recursive()不执行冗余ODB查找。

     

read-treecheckout等操作中,当提交之间的差异相对较小时,可能会有许多对等目录具有相同的OID。
  在这些情况下,我们可以避免多次针对相同的OID敲击ODB。

     

此补丁处理n = 2和n = 3个案例,只是复制数据而不是重复fill_tree_descriptor()。

================
  

在Windows repo(500K树,3.1M文件,450MB索引)上,当在两个提交之间循环并且单个文件不同时,这会将总时间减少0.75秒。

(avg) before: 22.699
(avg) after:  21.955
===============

答案 2 :(得分:1)

经过一番调查后,我得到的证据表明,糟糕的性能与来自不同域的用户拥有的文件有关。具体来说,我得出了以下结论:

  • 我在一个拥有多个域和数千名用户的企业环境中工作。
  • 由于组织变更,每个用户可能仅在过渡阶段保留在两个域中,即他或她的主域以及第二个域。通过Windows GUI更改对象所有权时,每个用户都会出现两次,其中一个必须转到扩展用户选择以标识分配给特定域的用户。
  • cygwin 启用了acl 会将“其他域”文件用户显示为“< domain> +< username>”。主域名self只是“< username>”。 Cygwin 没有acl 只显示“< username>”在这两种情况下。这可能相当令人困惑,因为cygwin识别的文件权限和所有权将表示写入权限,而用户实际上没有这个权限。
  • 属于“其他域”自我的文件可由我的“此域”自己写入,因此域分配在很大程度上是透明的。
  • 我们的版本控制系统中的一个大型源代码树(也在git repo中镜像)拥有数千个“其他域自我”所拥有的文件。这似乎导致文件操作缓慢。将所有权更改为“主域自身”可修复速度问题,无论是git还是其他文件访问。

我必须假设为其他域中的用户获取文件权限很慢,并且由于某种原因没有缓存(它始终是同一个用户)。

以下文章的其余部分是我最初发布的内容。我让它站起来。

对我来说(在一家拥有多个地理位置分散的Windows域名的大公司工作),罪魁祸首是默认情况下cygwin uses Windows acl。请考虑域中所有已知用户的此请求:

$ time (mkpasswd -D | wc -l)
45183

real    27m55,340s
user    0m1,637s
sys     0m0,123s

修复(1)(2)是使用noacl安装NTFS文件系统的简单问题,即我的/etc/fstab包含行

none / cygdrive binary,posix=0,user,noacl 0 0

(同时消除烦人的cygdrive前缀)。

我不禁想象cygwin / msys(除了Windows git安装默认情况下挂载noacl,可能出于这个原因),它会触及的每个文件执行域服务器查询缓存结果。

这一变化是在2015年左右推出的,其中包括cygwin 2.4或2.5。来自release notes for 2.4:

  

为了适应标准Windows ACL,使用Windows AuthZ API计算ACL中所有者和所有其他用户的POSIX权限。在某些情况下,可能会显着减慢POSIX权限的计算 [...](我强调)。

noacl选项将启动BeyondCompare(或回显字符串)的时间从25秒缩短为1.完全无法理解为什么同一文件上的简单git diff非常因为我天真地认为所需的信息以及所需的FS动作是相同的,所以即使使用acl也是如此。

我现在会查看cygserver,这可能会通过缓存来改善目标。

更新:不幸的是,cygserver没有改善这种情况。

(1)git的修复。 mkpasswd不受影响。

(2)我还没有理解和测试git(以及我们也通过cygwin访问的ClearCase视图)对文件权限和所有权的影响。我的直觉是,人们希望尽可能地保持对Windows语义的忠诚(意味着noacl可能会遇到问题)。

(3)cygwin documentation讨论了不缓存查询结果的场景。一个是由一系列cygwin进程组成的,这些进程不是从一个常见的cygwin祖先(如bash)产生的,而是来自像cmd这样的windows程序。我必须假设Windows为本机程序提供了缓存机制,否则Windows系统在此企业环境中将无法使用。出于某种原因,cygwin不使用它。