{"thread":{"id":"51587","subject":"[RFC PATCH 0/2] grep: make threading smarter","startedAt":"2019-08-04T21:15:35Z","lastAt":"2019-08-05T21:28:38Z","messageCount":4,"participants":["Carlo Marcelo Arenas Belón","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"379922","messageId":"20190804211509.39229-1-carenas@gmail.com","threadId":"51587","inReplyTo":null,"subject":"[RFC PATCH 0/2] grep: make threading smarter","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2019-08-04T21:15:07Z","receivedAt":"2019-08-04T21:15:35Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"833e3df171 (pack-objects: Add runtime detection of online CPU's, 2008-02-22)\nadded the capability to check the number of online CPUs at runtime to do\nbetter threading, so use that as well with grep.\n\nTesting with a large (more than 4) number of cores and no grep.threads\nconfiguration in real hardware encouraged, to confirm that no other\nbottleneck is preventing the additional threads to improve performance.\n\nIf platform specific testing shows degradation (specially with HP-UX),\nmake sure that the right number of CPUs is reported by :\n\n  $ ./t/helper/test-tool online-cpus\n  4\n\nThere are additional cleanups possible in the grep code but had left it\nout of this RFC to avoid confusion and make the change in patch 2 as\nstraight forward as possible.\n\nThere is also a chance that the online_cpus() function will be updated\nas it predates POSIX and might be associated with one known performance\nissue in HP-UX[1]\n\nLastly the performance numbers point to deficiencies in kwset and the\ncompat/regex code that will need to be addressed independently.\n\nCarlo Marcelo Arenas Belón (2):\n  p7810: add more grep performance relevant cases\n  grep: make default number of threads reflect runtime\n\n Documentation/git-grep.txt |  2 +-\n builtin/grep.c             |  3 +--\n t/perf/p7810-grep.sh       | 25 +++++++++++++++++++++++--\n 3 files changed, 25 insertions(+), 5 deletions(-)\n\n[1] https://public-inbox.org/git/TU4PR8401MB121664A8A588D799803F1E84E11E0@TU4PR8401MB1216.NAMPRD84.PROD.OUTLOOK.COM/\n-- \n2.23.0.rc1\n"},{"id":"379923","messageId":"20190804211509.39229-2-carenas@gmail.com","threadId":"51587","inReplyTo":"20190804211509.39229-1-carenas@gmail.com","subject":"[RFC PATCH 1/2] p7810: add more grep performance relevant cases","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2019-08-04T21:15:08Z","receivedAt":"2019-08-04T21:15:36Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"Add a baseline for a matching regex and make clear the distinction\nbetween fixed (now using kwset) and a real simple expression.\n\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n t/perf/p7810-grep.sh | 25 +++++++++++++++++++++++--\n 1 file changed, 23 insertions(+), 2 deletions(-)\n\ndiff --git a/t/perf/p7810-grep.sh b/t/perf/p7810-grep.sh\nindex 9f4ade639f..9a4e335659 100755\n--- a/t/perf/p7810-grep.sh\n+++ b/t/perf/p7810-grep.sh\n@@ -7,13 +7,34 @@ test_description=\"git-grep performance in various modes\"\n test_perf_large_repo\n test_checkout_worktree\n \n-test_perf 'grep worktree, cheap regex' '\n+test_perf 'grep worktree, fixed regex (no match)' '\n \tgit grep some_nonexistent_string || :\n '\n+test_perf 'grep worktree, fixed regex (common)' '\n+\tgit grep void || :\n+'\n+test_perf 'grep -I, fixed non binary regex (common)' '\n+\tgit grep -i void || :\n+'\n+test_perf 'grep -i, fixed caseless regex (common)' '\n+\tgit grep -i void || :\n+'\n+test_perf 'grep --no-index, fixed regex (common)' '\n+\tgit grep --no-index void || :\n+'\n+test_perf 'grep worktree, simple regex (common)' '\n+\tgit grep \"void|int\" || :\n+'\n+test_perf 'grep -I, simple non binary regex (common)' '\n+\tgit grep -I \"void|int\" || :\n+'\n+test_perf 'grep -i, simple caseless regex (common)' '\n+\tgit grep -i \"void|int\" || :\n+'\n test_perf 'grep worktree, expensive regex' '\n \tgit grep \"^.* *some_nonexistent_string$\" || :\n '\n-test_perf 'grep --cached, cheap regex' '\n+test_perf 'grep --cached, fixed regex' '\n \tgit grep --cached some_nonexistent_string || :\n '\n test_perf 'grep --cached, expensive regex' '\n-- \n2.23.0.rc1\n\n"},{"id":"379924","messageId":"20190804211509.39229-3-carenas@gmail.com","threadId":"51587","inReplyTo":"20190804211509.39229-1-carenas@gmail.com","subject":"[RFC PATCH 2/2] grep: make default number of threads reflect runtime","fromName":"Carlo Marcelo Arenas Belón","fromEmail":"carenas@gmail.com","sentAt":"2019-08-04T21:15:09Z","receivedAt":"2019-08-04T21:15:38Z","isPatch":true,"sender":{"key":"carenas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/76036?v=4"},"body":"5b594f457a (Threaded grep, 2010-01-25) added a hardcoded number of\nthreads(8) to use in grep and 89f09dd34e (grep: add --threads=<num>\noption and grep.threads configuration, 2015-12-15) made it configurable\nthrough a knob as a workaround for systems where that default was not\neffective.\n\nUse instead the industry standard of 2x number of CPUs (to allow for\nIO wait) for the default.\n\nUsing Debian 10 amd64 in a 2 CPU VirtualBox running in macOS 10.14.6\nand that might had been representative of the original author environment\nshows an overall performance improvement by avoiding thread trashing:\n\nTest                                                origin/maint        HEAD\n-----------------------------------------------------------------------------------------------\n7810.1: grep worktree, fixed regex (no match)       0.52(0.43+0.49)     0.50(0.44+0.46) -3.8%\n7810.2: grep worktree, fixed regex (common)         0.94(1.20+0.50)     0.91(1.24+0.44) -3.2%\n7810.3: grep -I, fixed non binary regex (common)    0.98(1.24+0.51)     0.94(1.30+0.44) -4.1%\n7810.4: grep -i, fixed caseless regex (common)      0.97(1.31+0.45)     0.93(1.18+0.56) -4.1%\n7810.5: grep --no-index, fixed regex (common)       1.02(1.28+0.50)     0.97(1.14+0.59) -4.9%\n7810.6: grep worktree, simple regex (common)        0.77(0.96+0.45)     0.73(0.88+0.48) -5.2%\n7810.7: grep -I, simple non binary regex (common)   0.78(0.96+0.48)     0.73(0.94+0.43) -6.4%\n7810.8: grep -i, simple caseless regex (common)     0.87(1.11+0.48)     0.82(1.16+0.38) -5.7%\n7810.9: grep worktree, expensive regex              10.37(19.67+0.76)   10.20(19.46+0.76) -1.6%\n7810.10: grep --cached, fixed regex                 4.48(4.37+0.10)     4.63(4.54+0.09) +3.3%\n7810.11: grep --cached, expensive regex             23.74(23.61+0.11)   23.39(23.28+0.09) -1.5%\n\nSigned-off-by: Carlo Marcelo Arenas Belón <carenas@gmail.com>\n---\n Documentation/git-grep.txt | 2 +-\n builtin/grep.c             | 3 +--\n 2 files changed, 2 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\nindex 2d27969057..5d72e03b2e 100644\n--- a/Documentation/git-grep.txt\n+++ b/Documentation/git-grep.txt\n@@ -60,7 +60,7 @@ grep.extendedRegexp::\n \n grep.threads::\n \tNumber of grep worker threads to use.  If unset (or set to 0),\n-\t8 threads are used by default (for now).\n+\t2 threads per core are used by default.\n \n grep.fullName::\n \tIf set to true, enable `--full-name` option by default.\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 580fd38f41..0ed8da30f8 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -32,7 +32,6 @@ static char const * const grep_usage[] = {\n \n static int recurse_submodules;\n \n-#define GREP_NUM_THREADS_DEFAULT 8\n static int num_threads;\n \n static pthread_t *threads;\n@@ -1068,7 +1067,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t} else if (num_threads < 0)\n \t\tdie(_(\"invalid number of threads specified (%d)\"), num_threads);\n \telse if (num_threads == 0)\n-\t\tnum_threads = HAVE_THREADS ? GREP_NUM_THREADS_DEFAULT : 1;\n+\t\tnum_threads = HAVE_THREADS ? online_cpus() * 2 : 1;\n \n \tif (num_threads > 1) {\n \t\tif (!HAVE_THREADS)\n-- \n2.23.0.rc1\n\n"},{"id":"379958","messageId":"xmqqa7cnmhds.fsf@gitster-ct.c.googlers.com","threadId":"51587","inReplyTo":"20190804211509.39229-3-carenas@gmail.com","subject":"Re: [RFC PATCH 2/2] grep: make default number of threads reflect runtime","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-08-05T21:28:31Z","receivedAt":"2019-08-05T21:28:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Carlo Marcelo Arenas Belón  <carenas@gmail.com> writes:\n\n> 5b594f457a (Threaded grep, 2010-01-25) added a hardcoded number of\n> threads(8) to use in grep and 89f09dd34e (grep: add --threads=<num>\n> option and grep.threads configuration, 2015-12-15) made it configurable\n> through a knob as a workaround for systems where that default was not\n> effective.\n>\n> Use instead the industry standard of 2x number of CPUs (to allow for\n> IO wait) for the default.\n\nThanks.  \n\nWhile I am not bold enough to endorse the \"industry standard is\ntwice the number of CPUs\" claim, my gut feeling agrees with you that\n8 threads may be too many for a 2 CPU box.\n\nI think we cap the parallelism to the number of CPUs (not twice\nthat) in all the codepaths that currently call online_cpus(), and\nsome codepaths even cap it further to avoid creating tasks that are\ntoo small (e.g. name-hash, index-pack).\n\nThere may not be a single one-size-fits-all scaling factor (as I/O\nbound jobs tend to do better with a bit more workers than there are\ncores, but adding more workers would not help when you are CPU\nbound), but we'd be better off to have a mechanism to allow us to\nlater have a consistent way to auto-scale the number of workers?\n\nRandom ideas include (not mutually exclusive)\n\n - accept \"[grep] threads = 2xCPU\", in addition to \"[grep] threads =\n   8\", to mean \"this many workers per CPUs\"?\n\n - add \"cpuBound.numThreads\" and \"ioBound.numThreads\" variables to\n   configure the number of workers for cpu and io bound jobs, so\n   that the users do not have to configure them for each command?\n\n - build an num_threads() API that is used by the current callers of\n   online_cpus(), including the new one this patch adds, perhaps\n   with a signature allows it to take configuration key (e.g. \"git\n   grep\" would pass \"grep.threads\") and if the task is expected to\n   be IO or CPU bound (\"git grep\" may pass \"I am heavy on IO\"), e.g.\n\n\tint num_threads(const char *config_key,\n\t\t\tenum { CPUBOUND, IOBOUND } task_type);\n\n   to hide the complexity of the first two items?\n\n> Using Debian 10 amd64 in a 2 CPU VirtualBox running in macOS 10.14.6\n> and that might had been representative of the original author environment\n> shows an overall performance improvement by avoiding thread trashing:\n\nThe above does not parse very well, at least to me.\n\n> diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\n> index 2d27969057..5d72e03b2e 100644\n> --- a/Documentation/git-grep.txt\n> +++ b/Documentation/git-grep.txt\n> @@ -60,7 +60,7 @@ grep.extendedRegexp::\n>  \n>  grep.threads::\n>  \tNumber of grep worker threads to use.  If unset (or set to 0),\n> -\t8 threads are used by default (for now).\n> +\t2 threads per core are used by default.\n>  \n>  grep.fullName::\n>  \tIf set to true, enable `--full-name` option by default.\n> diff --git a/builtin/grep.c b/builtin/grep.c\n> index 580fd38f41..0ed8da30f8 100644\n> --- a/builtin/grep.c\n> +++ b/builtin/grep.c\n> @@ -32,7 +32,6 @@ static char const * const grep_usage[] = {\n>  \n>  static int recurse_submodules;\n>  \n> -#define GREP_NUM_THREADS_DEFAULT 8\n>  static int num_threads;\n>  \n>  static pthread_t *threads;\n> @@ -1068,7 +1067,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n>  \t} else if (num_threads < 0)\n>  \t\tdie(_(\"invalid number of threads specified (%d)\"), num_threads);\n>  \telse if (num_threads == 0)\n> -\t\tnum_threads = HAVE_THREADS ? GREP_NUM_THREADS_DEFAULT : 1;\n> +\t\tnum_threads = HAVE_THREADS ? online_cpus() * 2 : 1;\n>  \n>  \tif (num_threads > 1) {\n>  \t\tif (!HAVE_THREADS)\n"}]}