GNU bug report logs - #32099
uniq: add hash-based implementation

Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.

Package: coreutils; Severity: wishlist; Reported by: "Kingsley G. Morse Jr." <kingsley@HIDDEN>; Keywords: notabug; merged with #32101; dated Sun, 8 Jul 2018 22:22:01 UTC; Maintainer for coreutils is bug-coreutils@HIDDEN.
Changed bug title to 'uniq: add hash-based implementation' from 'New uniq option for speed' Request was from Assaf Gordon <assafgordon@HIDDEN> to control <at> debbugs.gnu.org. Full text available.
Severity set to 'wishlist' from 'normal' Request was from Assaf Gordon <assafgordon@HIDDEN> to control <at> debbugs.gnu.org. Full text available.
Forcibly Merged 32099 32101. Request was from Assaf Gordon <assafgordon@HIDDEN> to control <at> debbugs.gnu.org. Full text available.
bug closed, send any further explanations to 32099 <at> debbugs.gnu.org and "Kingsley G. Morse Jr." <kingsley@HIDDEN> Request was from Assaf Gordon <assafgordon@HIDDEN> to control <at> debbugs.gnu.org. Full text available.
Severity set to 'wishlist' from 'normal' Request was from Assaf Gordon <assafgordon@HIDDEN> to control <at> debbugs.gnu.org. Full text available.
Added tag(s) notabug. Request was from Assaf Gordon <assafgordon@HIDDEN> to control <at> debbugs.gnu.org. Full text available.

Message received at 32099 <at> debbugs.gnu.org:


Received: (at 32099) by debbugs.gnu.org; 14 Jul 2018 03:03:17 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Fri Jul 13 23:03:17 2018
Received: from localhost ([127.0.0.1]:59374 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1feAq5-0006eU-67
	for submit <at> debbugs.gnu.org; Fri, 13 Jul 2018 23:03:17 -0400
Received: from outbound-smtp02.blacknight.com ([81.17.249.8]:57091)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <kingsley@HIDDEN>) id 1feAq3-0006eD-Dc
 for 32099 <at> debbugs.gnu.org; Fri, 13 Jul 2018 23:03:16 -0400
Received: from mail.blacknight.com (pemlinmail06.blacknight.ie [81.17.255.152])
 by outbound-smtp02.blacknight.com (Postfix) with ESMTPS id 8EA2D98B40
 for <32099 <at> debbugs.gnu.org>; Sat, 14 Jul 2018 03:03:09 +0000 (UTC)
Received: (qmail 28522 invoked from network); 14 Jul 2018 03:03:09 -0000
Received: from unknown (HELO debian1.loaner.com)
 (kingsley@HIDDEN@[97.113.25.140])
 by 81.17.254.9 with ESMTPSA (AES256-SHA encrypted, authenticated);
 14 Jul 2018 03:03:09 -0000
Received: from kingsley by debian1.loaner.com with local (Exim 4.90_1)
 (envelope-from <kingsley@HIDDEN>)
 id 1feApp-00057M-JI; Fri, 13 Jul 2018 20:03:01 -0700
Date: Fri, 13 Jul 2018 20:03:01 -0700
From: "Kingsley G. Morse Jr." <kingsley@HIDDEN>
To: Bernhard Voelker <mail@HIDDEN>
Subject: Testing with other options (Was: Benchmarks: Hashing ~70% faster )
Message-ID: <20180714030301.nfye24f77u5nnhmz@HIDDEN>
References: <20180708210356.c5fwiocbvdndkgxh@HIDDEN>
 <a499a8ae-df6d-8342-8d89-e105f6b2bc62@HIDDEN>
 <20180710042953.2w46nfztrxrg6gmi@HIDDEN>
 <12517fed-acc1-7935-403a-f0a6be3444a3@HIDDEN>
 <673eaa7f-a94f-7ded-f349-35a56ad3c3f8@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
In-Reply-To: <673eaa7f-a94f-7ded-f349-35a56ad3c3f8@HIDDEN>
User-Agent: NeoMutt/20170306 (1.8.0)
X-Spam-Score: -0.7 (/)
X-Debbugs-Envelope-To: 32099
Cc: 32099 <at> debbugs.gnu.org, Assaf Gordon <assafgordon@HIDDEN>,
 Paul Eggert <eggert@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.7 (-)

Hey Berny,

I like your suggestion of testing whether hashing
interferes with any other option.

I was glad to see the POSIX standard doesn't
explicitly require sorted input or output.

If someone writes the patch, I should be able to
test it, at least on up to 1 GB of input.

So,
Kingsley

On 07/12/2018 08:43, Bernhard Voelker wrote:
> On 07/10/2018 08:21 PM, Assaf Gordon wrote:
> > I would suggest several improvements to the measurements, to ensure
> > relevant information is conveyed:
> > 
> > 1.
> > [...]
> 
> great summary.  With the risk of mentioning already said aspects:
> 
> 7. Consider all the existing options, i.e. processing modes, of 'uniq' as well.
> This means, it has to be considered (upfront!) whether introducing an alternate
> way to do things - in this case hashing - only serves for the trivial case,
> or whether this would slow down or even contradict the processing with other
> options, currently:
> 
>   -c, --count           prefix lines by the number of occurrences
>   -d, --repeated        only print duplicate lines, one for each group
>   -D                    print all duplicate lines
>       --all-repeated[=METHOD]  like -D, but allow separating groups
>                                  with an empty line;
>                                  METHOD={none(default),prepend,separate}
>   -f, --skip-fields=N   avoid comparing the first N fields
>       --group[=METHOD]  show all items, separating groups with an empty line;
>                           METHOD={separate(default),prepend,append,both}
>   -i, --ignore-case     ignore differences in case when comparing
>   -s, --skip-chars=N    avoid comparing the first N characters
>   -u, --unique          only print unique lines
>   -z, --zero-terminated     line delimiter is NUL, not newline
>   -w, --check-chars=N   compare no more than N characters in lines
> 
> Without deeper thinking about it, especially the combinations with
> the --group, --repeated and --unique options might be problematic.
> 
> 8. Standards.  POSIX says:
>   http://pubs.opengroup.org/onlinepubs/9699919799/utilities/uniq.html
> 
>   The uniq utility shall read an input file comparing adjacent lines,
>   and write one copy of each input line on the output. The second and
>   succeeding copies of repeated adjacent input lines shall not be written.
> 
> This makes an assumption both on the input and output.
> 
> Regarding the input, this means that the processing just has to remember
> the previous line in order to decide whether to print/discard it in the
> output.  Therefore, arbitrary input size is fine.
> Hashing most probably will have issues with arbitrary input size;
> I do not talk about 1GB files, but _much_ larger files (yes, we
> are in 2018 where 1GB is like nothing).
> 
> Regarding the output, this means that the output is implicitly in
> sort order as well.  Like the input, uniq can discard the already
> written data from memory because it is sure that uniq doesn't need
> to consider it anymore.
> 
> 
> Thus said, a successful optimization idea does not only have to show
> that it is faster or needs less resources in _some_ cases, but also
> must prove that it does not tear down many cases including extreme
> ones.  The current implementation might be as-is for a good reason.
> If it turns out that the optimization idea screws up a single
> of the above use cases, then the dilemma is whether 2 implementations
> are warranted to be kept (maintenance!), and whether it is possible
> to detect the extreme cases early enough to switch from the default
> to the other processing strategy.
> 
> https://en.wikipedia.org/wiki/Perfect_is_the_enemy_of_good
> or D. Knuth:
>   "premature optimization is the root of all evil
>    (or at least most of it) in programming"
> 
> As Assaf said, a patch with a proof of concept would be helpful ... even
> if it's just helpful to proof that the current implementation is fine.
> 
> Have a nice day,
> Berny

-- 
Time is the fire in which we all burn.





Information forwarded to bug-coreutils@HIDDEN:
bug#32099; Package coreutils. Full text available.

Message received at 32099 <at> debbugs.gnu.org:


Received: (at 32099) by debbugs.gnu.org; 12 Jul 2018 06:44:22 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Thu Jul 12 02:44:22 2018
Received: from localhost ([127.0.0.1]:56256 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1fdVKv-0004nl-L1
	for submit <at> debbugs.gnu.org; Thu, 12 Jul 2018 02:44:21 -0400
Received: from mout.kundenserver.de ([217.72.192.73]:53115)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <mail@HIDDEN>) id 1fdVKt-0004nW-TX
 for 32099 <at> debbugs.gnu.org; Thu, 12 Jul 2018 02:44:20 -0400
Received: from [192.168.101.10] ([91.1.213.175]) by mrelayeu.kundenserver.de
 (mreue104 [212.227.15.183]) with ESMTPSA (Nemesis) id
 0MLyNI-1fiyyd0Giq-007i8f; Thu, 12 Jul 2018 08:44:03 +0200
Subject: Re: bug#32099: Benchmarks: Hashing ~70% faster (Was: New uniq option
 for speed)
To: Assaf Gordon <assafgordon@HIDDEN>,
 "Kingsley G. Morse Jr." <kingsley@HIDDEN>
References: <20180708210356.c5fwiocbvdndkgxh@HIDDEN>
 <a499a8ae-df6d-8342-8d89-e105f6b2bc62@HIDDEN>
 <20180710042953.2w46nfztrxrg6gmi@HIDDEN>
 <12517fed-acc1-7935-403a-f0a6be3444a3@HIDDEN>
From: Bernhard Voelker <mail@HIDDEN>
Openpgp: preference=signencrypt
Autocrypt: addr=mail@HIDDEN; prefer-encrypt=mutual; keydata=
 xsBNBFPirzMBCACyzYldTjQ4ufFOkByY5Nn5USb5GFoL48nWBwNHjd9KUbtRRNlQiPNKd6hK
 Gvd3BGi5aoFKA4ytfRk6jbAbW3jVb3R8wYaV08mOy4KVEKxqN4bxsXlMjNChXVR+rtKDmfI+
 oPTL+cPH2X6gW4W02IRbVw0uUhNm6zEedC/gNrY/mTlf1enZ46jxZ7BTUZaG+kx38UMISIMB
 zSzLRtdkwgmHj4jS3p1fF2cwRqLclIfMjKGpbNFPEXeXKWrCLcqHw78795eAR9q0YvrDkfIn
 GdDBwfb3VM4NdulwIFzvYZMSXvSbbyPLB5YkHU5aAWQHUse4WlfT5ccDpbzUYldRAvF9ABEB
 AAHNK0Jlcm5oYXJkIFZvZWxrZXIgPG1haWxAYmVybmhhcmQtdm9lbGtlci5kZT7CwHkEEwEC
 ACMFAlPirzMCGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIeAQIXgAAKCRBGUC73lpFxle5wCACC
 dbs0QaJ0vR3Sff2cKdTk41rUq3YfWngsR///IOU0C5DdkePmCnJE/lUsUy0LRTxcUDLxQR+x
 QHU8ssRT0JUO9726dI3miy36UdsgmBYaOtLvQcidGmW1R7o0PYYf04+TFtyqKgngOUBPpMgR
 6o4UsQxy/OD4bN1WDqOgIjL+D/qJpkKmgp6L6+hhaBCpiOFKRmmV7YyQ3SqVlfQNiHs5ZtkR
 nXpIjgZARV+GllKucI17bO0CGmTJZ1tstVy0+W3DQT1lbBkTTc++5LONM99D3jjn23l1ocOp
 folR53F7I4cb2RNfT23v1I59RH37lB9wMOqrKj0UjYAC2YoPGQ3BzsBNBFPirzMBCADXLWWp
 QihBldY6reca8ZKdc3T9qXEOa3akE3DWKztIBmNJhtYOjmpLYajQTkGa7UoJTnbmZE2Rn6ZE
 oNnvb0gcFNAIcY95KOI+bjOR8HEgh4cx2REXh6L6olIgyXqt/KFusE4wtVZAFxZl+30HzN6n
 D+1HvrjXxPJRX6MsIYOYyyX9/6OofwJK6QHODYGp8WL2olHDnmsXg4AT6Wlr7qKpKrQELlcF
 R4xkvdmgL/Ghw/tK0yJTxMIcewCCZWLPOXRmFRbvAadZWPAgVsJ63siNyUlVnVMSzDgTJl+s
 l/DMabXpqrJQx3/1Yy6mTaDs3XZT/wmBKaTLXx/LByaPxQQ7ABEBAAHCwF8EGAECAAkFAlPi
 rzMCGwwACgkQRlAu95aRcZWVPwgAqZT6iTXkoP37wYb41323RzhBcJ8JSk4cyBDBUXX0lMrM
 3qhiClKG7phpxVdu817Gwc6Hsecg7FfjQAV8MHQ0ZFeEFdk3b2rKBqfsStc+h49/xF3Fb+if
 CzR9qeQF82fMSxkg18++7hMcHCMO/hPZ/Q0xRi+lrSr2QKDJQuLzSyVU14TxrCkevZjEhtma
 VNvcJlJzCbiBXee9Fpc5jITUXPFG8E8dxqo1n+duOyIMgozrAnzP7X5V/Ob/Ozf/aGGX9+Jd
 inyfCX18nWcHALKMU/36Eua/ylalf/2c2YkBp9KCLVmGgPkUgW52EeRPgroIsiwu+rwCSV6Z
 UyCJ+OymCg==
Message-ID: <673eaa7f-a94f-7ded-f349-35a56ad3c3f8@HIDDEN>
Date: Thu, 12 Jul 2018 08:43:59 +0200
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
 Thunderbird/52.9.0
MIME-Version: 1.0
In-Reply-To: <12517fed-acc1-7935-403a-f0a6be3444a3@HIDDEN>
Content-Type: text/plain; charset=utf-8
Content-Language: en-US
Content-Transfer-Encoding: 8bit
X-Provags-ID: V03:K1:vPiac2B3cGEqdoQsIymHUy3lxmqSF2B4WoRnjZoUJeAnOnGQ/jC
 B5+7wfEO90ojUTI2Sh4I2eZ076RL52E/uKrATuby2JNFdesFV9H8G/wN5+C3c9dhkahb4M8
 olnzhgxYX4UQRHFNS1Fo5D8vc0h0bQR71K3tpUKPdyQBMCSuc5vJ1DqtOyUM1rRQp+1XaPm
 SOMCMWVVac65XWFX78HuQ==
X-UI-Out-Filterresults: notjunk:1;V01:K0:V8uB0LtrHHY=:RhRUY/NFZLEbmITQuAv+xa
 DC5h41QgiZSr9ESTsR+v9iK8Kw2yqEKd80UkzYLank8yzqaUH3CUX9AOcBuXSvdm4s5gb6nSn
 kftVy+vZSfOIHqmFDpmsHCFDn8toGeDRkHpPW+O373R5DW7FcdDwPiKJBRVuys/gxLo84nJU9
 BJBDzcRvUu83+mBWcnkthjyOlsFybY9NmBmoap/DTwy/ul4sP490ByAxLH/YRrAyFQqarhsA2
 sk9gXtdWVRdAmY3FBI+nhoLXW813v4VShsinnPRWPPP6cGd8Nq6dUGb3tQ462uh4EQDyawQJ/
 k32e+gL2DEsonROV43Jf3rrnMrtaynFZt2XJPIcTrS3yV6k5iWhUlsqIzT2P+1QjP0jCYR95Y
 eSwoNuJvvAgond9t/dwKgry32/2ZMiWaM+uI3kPkwxdJepiSorAX4rqzWtpnO/dVVZeIa5TmK
 qmhatoPq1IYQK0AQNqMYteCzivolpJeCGVkgi8BRV47bgax5xVWVebLryLGvM+jmXNDpjFAsi
 PQOhr63if2WkHQaPYHMx+IjfKCVkM9F5QC8wLpiBQF5XwvW1b9tva9CxCk7rNyX2sC5//ldPu
 yJfoBHZtGU4vEji8ALkIKQk/IZeHSXITdl05qSsiRxly9ArzFd+uFRwyrL2Iz7ZiAIpCX71jW
 RQVqZetinrZJID3GZiuRENy7e2YJwO93e/5EfEkXH4fSaqmh+cwl9ewn2uaEiZlN5ylSFZvLC
 Y8BHHnRClEwfI1wX
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 32099
Cc: 32099 <at> debbugs.gnu.org, Paul Eggert <eggert@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

On 07/10/2018 08:21 PM, Assaf Gordon wrote:
> I would suggest several improvements to the measurements, to ensure
> relevant information is conveyed:
> 
> 1.
> [...]

great summary.  With the risk of mentioning already said aspects:

7. Consider all the existing options, i.e. processing modes, of 'uniq' as well.
This means, it has to be considered (upfront!) whether introducing an alternate
way to do things - in this case hashing - only serves for the trivial case,
or whether this would slow down or even contradict the processing with other
options, currently:

  -c, --count           prefix lines by the number of occurrences
  -d, --repeated        only print duplicate lines, one for each group
  -D                    print all duplicate lines
      --all-repeated[=METHOD]  like -D, but allow separating groups
                                 with an empty line;
                                 METHOD={none(default),prepend,separate}
  -f, --skip-fields=N   avoid comparing the first N fields
      --group[=METHOD]  show all items, separating groups with an empty line;
                          METHOD={separate(default),prepend,append,both}
  -i, --ignore-case     ignore differences in case when comparing
  -s, --skip-chars=N    avoid comparing the first N characters
  -u, --unique          only print unique lines
  -z, --zero-terminated     line delimiter is NUL, not newline
  -w, --check-chars=N   compare no more than N characters in lines

Without deeper thinking about it, especially the combinations with
the --group, --repeated and --unique options might be problematic.

8. Standards.  POSIX says:
  http://pubs.opengroup.org/onlinepubs/9699919799/utilities/uniq.html

  The uniq utility shall read an input file comparing adjacent lines,
  and write one copy of each input line on the output. The second and
  succeeding copies of repeated adjacent input lines shall not be written.

This makes an assumption both on the input and output.

Regarding the input, this means that the processing just has to remember
the previous line in order to decide whether to print/discard it in the
output.  Therefore, arbitrary input size is fine.
Hashing most probably will have issues with arbitrary input size;
I do not talk about 1GB files, but _much_ larger files (yes, we
are in 2018 where 1GB is like nothing).

Regarding the output, this means that the output is implicitly in
sort order as well.  Like the input, uniq can discard the already
written data from memory because it is sure that uniq doesn't need
to consider it anymore.


Thus said, a successful optimization idea does not only have to show
that it is faster or needs less resources in _some_ cases, but also
must prove that it does not tear down many cases including extreme
ones.  The current implementation might be as-is for a good reason.
If it turns out that the optimization idea screws up a single
of the above use cases, then the dilemma is whether 2 implementations
are warranted to be kept (maintenance!), and whether it is possible
to detect the extreme cases early enough to switch from the default
to the other processing strategy.

https://en.wikipedia.org/wiki/Perfect_is_the_enemy_of_good
or D. Knuth:
  "premature optimization is the root of all evil
   (or at least most of it) in programming"

As Assaf said, a patch with a proof of concept would be helpful ... even
if it's just helpful to proof that the current implementation is fine.

Have a nice day,
Berny




Information forwarded to bug-coreutils@HIDDEN:
bug#32099; Package coreutils. Full text available.

Message received at 32099 <at> debbugs.gnu.org:


Received: (at 32099) by debbugs.gnu.org; 11 Jul 2018 23:43:28 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Wed Jul 11 19:43:28 2018
Received: from localhost ([127.0.0.1]:56075 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1fdOlb-0001Gr-Am
	for submit <at> debbugs.gnu.org; Wed, 11 Jul 2018 19:43:27 -0400
Received: from outbound-smtp08.blacknight.com ([46.22.139.13]:60177)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <kingsley@HIDDEN>) id 1fdOlX-0001Gb-Ck
 for 32099 <at> debbugs.gnu.org; Wed, 11 Jul 2018 19:43:24 -0400
Received: from mail.blacknight.com (pemlinmail03.blacknight.ie [81.17.254.16])
 by outbound-smtp08.blacknight.com (Postfix) with ESMTPS id
 7C2A21C2D74
 for <32099 <at> debbugs.gnu.org>; Thu, 12 Jul 2018 00:43:17 +0100 (IST)
Received: (qmail 27275 invoked from network); 11 Jul 2018 23:43:17 -0000
Received: from unknown (HELO debian1.loaner.com)
 (kingsley@HIDDEN@[97.113.25.140])
 by 81.17.254.9 with ESMTPSA (AES256-SHA encrypted, authenticated);
 11 Jul 2018 23:43:16 -0000
Received: from kingsley by debian1.loaner.com with local (Exim 4.90_1)
 (envelope-from <kingsley@HIDDEN>)
 id 1fdOlJ-0007Mf-Aa; Wed, 11 Jul 2018 16:43:09 -0700
Date: Wed, 11 Jul 2018 16:43:09 -0700
From: "Kingsley G. Morse Jr." <kingsley@HIDDEN>
To: Assaf Gordon <assafgordon@HIDDEN>
Subject: datamash wins! (Was: New uniq option for speed)
Message-ID: <20180711234309.jaq663dsktjljkoa@HIDDEN>
References: <20180708210356.c5fwiocbvdndkgxh@HIDDEN>
 <a499a8ae-df6d-8342-8d89-e105f6b2bc62@HIDDEN>
 <20180710042953.2w46nfztrxrg6gmi@HIDDEN>
 <12517fed-acc1-7935-403a-f0a6be3444a3@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="3auohxm5ypw3cvru"
Content-Disposition: inline
In-Reply-To: <12517fed-acc1-7935-403a-f0a6be3444a3@HIDDEN>
User-Agent: NeoMutt/20170306 (1.8.0)
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 32099
Cc: 32099 <at> debbugs.gnu.org, Paul Eggert <eggert@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)


--3auohxm5ypw3cvru
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hey Assaf,

Thank you very much for taking the time to share
your thoughts.

People like you, willing to improve free software
and help the common good, restore my faith in
humanity.


I followed much of your advice.

I ran more benchmarks: 

gawk, mawk, sort -u, sort | uniq and ... datamash rmdup!

Plus, I benchmarked them against a bigger file.

~1 GB!

Plus, plus, I measured how much memory they used!


The result?

Hashing algorithms always won.

I expected it.

When I benchmarked data compression apps, one
named "rzip" that searched its cache of unique
values with hashing was much faster.

    https://www.linuxjournal.com/article/8051


But, to be fair, I was surprised by how little
memory datamash seemed to use.

Maybe I screwed up.

I checked max resident set size of the process
during its lifetime with /usr/bin/time's "%M"
specifier.


Plus, plus, plus, I created a composite
performance criteria of 

    elapsed time * memory used

(It's in the attached spread sheet.)

That winner at ~1 GB?

datamash!

No matter whether the keys were unique or
duplicated, "datamash rmdup 1" won!

New files are attached.


Humble suggestion:

Don't worry about running out of memory.

Hashing could be added to the "uniq" command as...
(wait for it...) an option.

So you could always omit it and use sort.


For yours truly, the big gain is actually being
able to ditch sort.

Less is more.

It's a UNIX thing.


So it is said.

So it is done.

Sorting is great, but

less is number one!

~K

PS: Congratulations on datamash performing so
    well.

On 07/10/2018 12:21, Assaf Gordon wrote:
> tag 32099 notabug
> severity 32099 wishlist
> close 32099
> stop
> 
> Hello Kingsley,
> 
> On 09/07/18 10:29 PM, Kingsley G. Morse Jr. wrote:
> > And I like your benchmarks.
> > 
> > Mine are humbly attached.
> > 
> > They compare sorting to hashing.
> > 
> > At the moment, hashing seems to me to be about 70%
> > faster.
> > 
> > And to scale better.
> > 
> > I'd still like uniq to be faster and free from
> > sort.
> 
> Thank you for taking the time to create and provide these,
> including the scripts to reproduce it.
> 
> I've marked this item as "closed / wishlist" - but only because it
> is technically not a bug report. Discussion is welcomed to continue
> by replying to this thread.
> 
> Being "faster" alone is important but not the only criteria (as
> mentioned in the previous email's examples).
> 
> Your measurements are a good start towards stronger support to
> hash-based uniq implementation (a working patch, btw, would be even
> stronger).
> 
> I would suggest several improvements to the measurements, to ensure
> relevant information is conveyed:
> 
> 1.
> Specify exactly which versions of awk/sort you are using
> (e.g. which versions, whether from your distribution or compiled from
> source, if compiled than which compiler / optimization flags).
> What CPUs is being used, how much memory does the computer have, etc.
> 
> 2.
> I would suggest adding "sort | uniq" to the charts, because that is the
> real base-line you are trying to improve.
> I would also consider adding "datamash rmdup" to the charts, because its
> hash-based implementation could serve as a ball-park indication of how
> a naive hash implementation would work in uniq.
> 
> 3.
> You input is very small (up to 90K lines of 10 characters each) - that
> does not seem to stress-test any significant parts of the algorithms
> (and for a typical user, waiting 0.05 seconds vs 0.15 seconds does not
> matter).
> 
> I would recommend much larger input files, with much longer lines -
> trying to simulate various real-world scenarios.
> 
> Here's a project of someone who tried to compare various hashing
> functions: https://github.com/jhunt/hash/
> Under the "corpus" directory you'll find few demo data files.
> Even the largest one (qnames) is only 84MB - not very big.
> 
> Perhaps consider duplicating the content few times, then test it:
>   for i in $(seq 1 5);do cat qnames; done > input
> 
> To get even closer to real-world input, try several input files
> with different ratios of duplicated lines (your script create completely
> random data - not very similar to real-world input files).
> 
> For example, what happens with many lines share similar sub-strings?
> depending on the hashing implementation, this could lead to lower
> performance.
> 
> 4.
> It would be beneficial to see what's the memory requirements and limits
> of a hash-based implementation. Currently, because 'sort' is not limited
> by available RAM, there is no memory limit (though resorting to disk I/O
> might make everything slow).
> For example, is it possible to hash an 800M file on a machine with only 1GB
> of RAM ? and without additional code, hashing files larger than available
> memory is simply not possible - a very big disadvantage.
> 
> 5.
> To compare "sort' fairly against other options,
> I would add to the measurements using "--parallel 1" and later "--parallel
> N" (N being the number of cpu/cores you have).
> Does that improve performance?
> 
> The "awk" (or datamash) programs do not have a built-in memory limit,
> while sort does. It would be useful to specify a large amount of
> memory for sort (using "-S") to ensure sort did not revert to disk I/O.
> 
> 6.
> The reported time in your script is the elapsed time (aka "wall time").
> A more relevant option would be "user time" + "kernel time"
> (optiosn %S and %U in "time -f") - the wall time can be affected by
> factors that don't immediately relate to hashing/sorting performance.
> 
> 7.
> In your script you are providing a file-based input,
> it might be useful to clear the kernel's cache before each run
> to ensure these do not affect the results (especially when dealing with
> large files).
> See: https://www.tecmint.com/clear-ram-memory-cache-buffer-and-swap-space-on-linux/
> 
> 
> 
> 
> To conclude,
> There is definitely merit in trying to optimize uniq's performance,
> but it must be weighed against other factors (e.g. the ability to 'uniq'
> a file larger than available memory, and the ease of using existing programs
> to achieve the same effect).
> 
> IMHO it is not a top-priority, so I don't want to give the impression
> that if an amazing speed improvement is presented, uniq will be swiftly
> rewritten.
> 
> But of course, a working patch and strong pro arguments would go a long
> way towards incorporating this feature.
> 
> regards,
>  - assaf
> 
> 
> 

-- 
Time is the fire in which we all burn.


--3auohxm5ypw3cvru
Content-Type: text/plain; charset=us-ascii
Content-Description: updated benchmarking script
Content-Disposition: attachment; filename=uniq_demo

# Report heading.
echo 'lines,line length,percent unique,algorithm,time(sec),memory(K)'

# Benchmark with increasing lines of data...
for data_lines in 1 10 100 1000 10000 100000 1000000 ; do

    # Benchmark with increasing line length..
    for line_length in 1 10 100 1000 ; do

        # Synchronize cached writes to persistent storage
        sync
        
        # Generate a certain number of lines of random data of a certain length
        tr -cd '[[:alnum:]]' < /dev/urandom | fold -bw "$line_length" | head -n "$data_lines" > /tmp/data

        # Calculate the percentage of lines that are unique.
        number_of_unique_lines="$( sort -u /tmp/data | wc -l )"
        percent_unique="$( calc -dp "$number_of_unique_lines/$data_lines" )"

        # Benchmark sort with its unique option.
        /usr/bin/time -o /tmp/sort_time -f %e,%M sort -u /tmp/data > /dev/null 
        echo "$data_lines,$line_length,$percent_unique,sort,$( cat /tmp/sort_time )"

        # Benchmark gawk hashing.
        /usr/bin/time -o /tmp/gawk_time -f %e,%M gawk '!seen[$0]++' /tmp/data  > /dev/null
        echo "$data_lines,$line_length,$percent_unique,gawk,$( cat /tmp/gawk_time )"

        # Benchmark mawk hashing.
        /usr/bin/time -o /tmp/mawk_time -f %e,%M mawk '!seen[$0]++' /tmp/data  > /dev/null
        echo "$data_lines,$line_length,$percent_unique,mawk,$( cat /tmp/mawk_time )"

        # Benchmark datamash.
        /usr/bin/time -o /tmp/datamash_time -f %e,%M cat /tmp/data | datamash rmdup 1 > /dev/null
        echo "$data_lines,$line_length,$percent_unique,datamash,$( cat /tmp/datamash_time )"

        # Benchmark a pipe of sort and unique.
        /usr/bin/time -o /tmp/sort_and_uniq_time -f %e,%M sort /tmp/data | uniq > /dev/null
        echo "$data_lines,$line_length,$percent_unique,sort and uniq,$( cat /tmp/sort_and_uniq_time )"

    done
done

--3auohxm5ypw3cvru
Content-Type: application/gnumeric
Content-Description: updated gnumeric spread sheet
Content-Disposition: attachment; filename="hash_and_sort_benchmarks.2.gnumeric"
Content-Transfer-Encoding: base64

H4sIAAAAAAAAA+3da2/bSJYG4O/9K7RqYDA72MiqKhYvno4H7sRJjHWcwHZ37/RiYSgSY3Mj
iR6KzmV+/RYpWbRk1dE5fAnMTvf0LgYRRR6V+Iq3R0f0D3/5Opv2PqfFIsvnz/tqMOz30vk4
n2Tzm+f9n65ePYv7fzn67oeb+ezwl7z49CHPP/XcIvPFoZv0vH9blneHBwdfvnwZ3MzvZ2mR
jQd5cXPwWQ0Hk3LSX837dZFtzPvF1HPp4VAd/Nfbs8vxbTobPcvmi3I0H6duqUV2uKgnnuXj
UVmPzftSyeDrYtI/+q7Xq4f58/LN9E7u8vGte0v93tvR/+aF+5d2/8zm1T9N0u+9up9Oq3es
9MA9PFgvf1yWRfbhvkwX1aTtictpq6nz0Sw9elgtP2fpl8PDxW3+5fo2L7K/5/NyNL1ejIt8
Ov0wKn44WC/xuMTn0fQ+Pbq6+OlkOcPy8fKFD3a8covRuHTLbPz/YyzzvEyrSdfl6MPiHzKM
SX49ui/z63E+u5um1UfrHzKMbHF9V7iVMS7TCTmAV8dnl6wRbE2qP70/5B8/ZuPUvemx22Lm
5bNZWo5W2+Tyqef9+2J+mI8W2aIeweKwHB/md+n8YZHDx3Mf1juI1TY9zeafdm3VKkmSg/rZ
h1kn4/V8d/fFtJ5rMj5Ip2n1CosDtxEePMxbjZA7qGrex0PK83z9QtXsy0E/7GqCg+Xjfm/1
Zh7t9nR/tV5XT1WV12FMxoeTkVvJeqjiZ8PomVJXenio7KFRv/5w8PDsw9z1oMZFWu+2nm0v
qJJD9/+BdQvumHGV7dYg1hM2YlzvsF6MpuP7aV3F7erm96PpReo2d7fO3Yo5mY8+TNPTMi1W
u9F6f/h1PWHhpgzdfOsJV/nU/WtefTKGA7d/djvKaT4qL0aT7Ovzvl49fJndZKVb1ppHe87L
2zQtz11ep/NJ+vXRVrF+olePN5+6JbUN+/XDi/yLexhaa8L+0f08+9v1JJ3lg2l+M9DLz/R6
8eZj/vSl6hd6neZu1RTfer9kk7La+QeBe29v0uzmtnSDjZLt0S62R9l7mS3upqNvr/Ji5lbq
ol6Jb7JJ+mta5OsHr4tssn7g3s+bdDRJi/UU95YeTVlVfHdfum0iXdQRrB5cfpt9cGvjx3Sa
f9kx/WI5bjf952yRfcimWfntef/1+dvryzcnJ1fXP59env54enZ69dflP89O+r1qaG5E1VFu
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

--3auohxm5ypw3cvru
Content-Type: text/plain; charset=us-ascii
Content-Description: new benchmark results
Content-Disposition: attachment; filename="uniq_demo.log.2"

lines,line length,percent unique,algorithm,time(sec),memory(K)
1,1,1,sort,0.00,1848
1,1,1,gawk,0.00,3424
1,1,1,mawk,0.00,1780
1,1,1,datamash,0.00,1580
1,1,1,sort and uniq,0.00,1828
1,10,1,sort,0.00,1916
1,10,1,gawk,0.00,3352
1,10,1,mawk,0.00,1832
1,10,1,datamash,0.00,1560
1,10,1,sort and uniq,0.00,1828
1,100,1,sort,0.00,1940
1,100,1,gawk,0.00,3324
1,100,1,mawk,0.00,1680
1,100,1,datamash,0.00,1564
1,100,1,sort and uniq,0.00,1904
1,1000,1,sort,0.00,1788
1,1000,1,gawk,0.00,3312
1,1000,1,mawk,0.00,1740
1,1000,1,datamash,0.00,1704
1,1000,1,sort and uniq,0.00,1916
10,1,0.9,sort,0.00,1780
10,1,0.9,gawk,0.00,3412
10,1,0.9,mawk,0.00,1628
10,1,0.9,datamash,0.00,1584
10,1,0.9,sort and uniq,0.00,1840
10,10,1,sort,0.00,1864
10,10,1,gawk,0.00,3444
10,10,1,mawk,0.00,1792
10,10,1,datamash,0.00,1616
10,10,1,sort and uniq,0.00,1928
10,100,1,sort,0.00,1792
10,100,1,gawk,0.00,3252
10,100,1,mawk,0.00,1784
10,100,1,datamash,0.00,1620
10,100,1,sort and uniq,0.00,1964
10,1000,1,sort,0.00,1972
10,1000,1,gawk,0.00,3248
10,1000,1,mawk,0.00,1772
10,1000,1,datamash,0.00,1640
10,1000,1,sort and uniq,0.00,1948
100,1,0.49,sort,0.00,1920
100,1,0.49,gawk,0.00,3516
100,1,0.49,mawk,0.00,1636
100,1,0.49,datamash,0.00,1616
100,1,0.49,sort and uniq,0.00,1828
100,10,1,sort,0.00,1968
100,10,1,gawk,0.00,3548
100,10,1,mawk,0.00,1696
100,10,1,datamash,0.00,1668
100,10,1,sort and uniq,0.00,1924
100,100,1,sort,0.00,1916
100,100,1,gawk,0.00,3536
100,100,1,mawk,0.00,1776
100,100,1,datamash,0.00,1632
100,100,1,sort and uniq,0.00,1928
100,1000,1,sort,0.00,1868
100,1000,1,gawk,0.00,3544
100,1000,1,mawk,0.00,1852
100,1000,1,datamash,0.00,1664
100,1000,1,sort and uniq,0.00,1784
1000,1,0.064,sort,0.00,1796
1000,1,0.064,gawk,0.00,3464
1000,1,0.064,mawk,0.00,1688
1000,1,0.064,datamash,0.00,1564
1000,1,0.064,sort and uniq,0.00,1920
1000,10,1,sort,0.00,1876
1000,10,1,gawk,0.00,3476
1000,10,1,mawk,0.00,1816
1000,10,1,datamash,0.00,1708
1000,10,1,sort and uniq,0.00,1804
1000,100,1,sort,0.00,2020
1000,100,1,gawk,0.00,3488
1000,100,1,mawk,0.00,1984
1000,100,1,datamash,0.00,1644
1000,100,1,sort and uniq,0.00,1948
1000,1000,1,sort,0.00,2724
1000,1000,1,gawk,0.00,4620
1000,1000,1,mawk,0.00,2876
1000,1000,1,datamash,0.01,1568
1000,1000,1,sort and uniq,0.01,2836
10000,1,0.0064,sort,0.01,1880
10000,1,0.0064,gawk,0.00,3564
10000,1,0.0064,mawk,0.00,1628
10000,1,0.0064,datamash,0.00,1616
10000,1,0.0064,sort and uniq,0.01,1876
10000,10,1,sort,0.03,1944
10000,10,1,gawk,0.02,4904
10000,10,1,mawk,0.00,2484
10000,10,1,datamash,0.01,1664
10000,10,1,sort and uniq,0.02,1884
10000,100,1,sort,0.02,3076
10000,100,1,gawk,0.01,5636
10000,100,1,mawk,0.00,3352
10000,100,1,datamash,0.02,1564
10000,100,1,sort and uniq,0.03,3036
10000,1000,1,sort,0.05,11644
10000,1000,1,gawk,0.06,14328
10000,1000,1,mawk,0.03,12232
10000,1000,1,datamash,0.09,1728
10000,1000,1,sort and uniq,0.10,11772
100000,1,0.00064,sort,0.20,4252
100000,1,0.00064,gawk,0.04,3332
100000,1,0.00064,mawk,0.01,1756
100000,1,0.00064,datamash,0.01,1728
100000,1,0.00064,sort and uniq,0.21,4252
100000,10,1,sort,0.29,5192
100000,10,1,gawk,0.14,17040
100000,10,1,mawk,0.13,8284
100000,10,1,datamash,0.04,1520
100000,10,1,sort and uniq,0.27,5188
100000,100,1,sort,0.34,13904
100000,100,1,gawk,0.18,26404
100000,100,1,mawk,0.15,17348
100000,100,1,datamash,0.10,1708
100000,100,1,sort and uniq,0.34,13836
100000,1000,1,sort,0.58,101788
100000,1000,1,gawk,0.62,113672
100000,1000,1,mawk,0.42,105888
100000,1000,1,datamash,0.73,1564
100000,1000,1,sort and uniq,0.84,101720
1000000,1,0.000064,sort,1.29,34940
1000000,1,0.000064,gawk,0.44,3304
1000000,1,0.000064,mawk,0.15,1752
1000000,1,0.000064,datamash,0.10,1568
1000000,1,0.000064,sort and uniq,1.33,35088
1000000,10,1,sort,2.66,43728
1000000,10,1,gawk,1.65,138700
1000000,10,1,mawk,1.79,65772
1000000,10,1,datamash,0.44,1620
1000000,10,1,sort and uniq,2.37,44008
1000000,100,1,sort,2.91,131600
1000000,100,1,gawk,2.10,232412
1000000,100,1,mawk,2.32,157876
1000000,100,1,datamash,1.23,1704
1000000,100,1,sort and uniq,3.64,131592
1000000,1000,1,sort,5.36,1010664
1000000,1000,1,gawk,6.53,1107508
1000000,1000,1,mawk,5.23,1042296
1000000,1000,1,datamash,7.79,1620
1000000,1000,1,sort and uniq,7.76,1010804

--3auohxm5ypw3cvru--




Information forwarded to bug-coreutils@HIDDEN:
bug#32099; Package coreutils. Full text available.

Message received at 32099 <at> debbugs.gnu.org:


Received: (at 32099) by debbugs.gnu.org; 10 Jul 2018 18:21:25 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Jul 10 14:21:25 2018
Received: from localhost ([127.0.0.1]:54337 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1fcxGO-0007uY-NB
	for submit <at> debbugs.gnu.org; Tue, 10 Jul 2018 14:21:25 -0400
Received: from mail-pf0-f193.google.com ([209.85.192.193]:35516)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <assafgordon@HIDDEN>) id 1fcxGN-0007uJ-97
 for 32099 <at> debbugs.gnu.org; Tue, 10 Jul 2018 14:21:23 -0400
Received: by mail-pf0-f193.google.com with SMTP id q7-v6so15544691pff.2
 for <32099 <at> debbugs.gnu.org>; Tue, 10 Jul 2018 11:21:23 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
 h=subject:to:cc:references:from:message-id:date:user-agent
 :mime-version:in-reply-to:content-language:content-transfer-encoding;
 bh=Wpac84Wp3ytdwo+YpMknwNKNVIHRzjx3qHWVQ9t6SVQ=;
 b=PyKRr1DYxN09bshtZtsPsGk5yBDyfw54pSAmGjpnaaXMDZ+xy5c2OudaGWlPgI9jbs
 Gzj0B0fY5eaRDEPRf0ZITjxj9XpU0dNm/0NMZh2iZzoIEWIUiF+3oTOc1Ma94z9PdvY/
 ulCLJZ3Gei7y5tKsnIn4+2Q6RH4KHnYFSFEhEEjLYO3zLvf6Np3HeNotv9I7stl4/YBB
 tHlLHYpR7GIe3/nBiQqYodZE/g1w5G87CZyWZmppk/T42CEbaCFbXJdSFMkpsvfKIZCS
 eNTdoMKZuxUkRB71P2oeZ6jEYp2YpX6wkFrQDD0vFZd4owqIAF9heAdAsvzuhxrg9GfG
 f8sg==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20161025;
 h=x-gm-message-state:subject:to:cc:references:from:message-id:date
 :user-agent:mime-version:in-reply-to:content-language
 :content-transfer-encoding;
 bh=Wpac84Wp3ytdwo+YpMknwNKNVIHRzjx3qHWVQ9t6SVQ=;
 b=qGXPiY7M20gBjNtiCdadME+DnGLMBd1K9EeXIxRt824L3Fe6zqOXEIJhc8UG1INV9l
 i2h0PusoofFOyf6DaZH4Rrb9CHZaZ98hFaUrST82wQXkG6D7MpMPFKrvTYPOd8mxikAL
 ANkrx7sZehc24iV32YJDi7tl0nmTcks0tRl344iDizwClLb/gY+2vf8w13kZIDpyBhso
 u2OXWoi6+OqiFsaih0e9kTUoRDJvuXBmITXkuxtmIESk82UO2CRaidJfM0sqWbTAAde5
 7C4H4/qQK6UVWGXINLGVrgmln4dMGl5/UbnkYSKPErNivqXIWzqcRkmA6BPvb0mmOj3y
 7ecA==
X-Gm-Message-State: APt69E0IJqZFBvhoLAWpwzeRfZfeorJ6JPx1u0nxZFUedLZvm9ltUMmr
 avEGytPlyHYaHwMLzKgG/2Y=
X-Google-Smtp-Source: AAOMgpfmm6OQEcstrr/IvgNQBZsDZMUASqp5m/kSuBC5pHn5IGX5RtW1GX9zqLysp4UkR/rrKw7cIQ==
X-Received: by 2002:a63:4c21:: with SMTP id
 z33-v6mr2382564pga.383.1531246877080; 
 Tue, 10 Jul 2018 11:21:17 -0700 (PDT)
Received: from tomato.housegordon.com (moose.housegordon.com. [184.68.105.38])
 by smtp.googlemail.com with ESMTPSA id
 p26-v6sm34607987pfi.164.2018.07.10.11.21.14
 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
 Tue, 10 Jul 2018 11:21:15 -0700 (PDT)
Subject: Re: bug#32099: Benchmarks: Hashing ~70% faster (Was: New uniq option
 for speed)
To: "Kingsley G. Morse Jr." <kingsley@HIDDEN>
References: <20180708210356.c5fwiocbvdndkgxh@HIDDEN>
 <a499a8ae-df6d-8342-8d89-e105f6b2bc62@HIDDEN>
 <20180710042953.2w46nfztrxrg6gmi@HIDDEN>
From: Assaf Gordon <assafgordon@HIDDEN>
Message-ID: <12517fed-acc1-7935-403a-f0a6be3444a3@HIDDEN>
Date: Tue, 10 Jul 2018 12:21:14 -0600
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
 Thunderbird/52.8.0
MIME-Version: 1.0
In-Reply-To: <20180710042953.2w46nfztrxrg6gmi@HIDDEN>
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Language: en-US
Content-Transfer-Encoding: 7bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 32099
Cc: 32099 <at> debbugs.gnu.org, Paul Eggert <eggert@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

tag 32099 notabug
severity 32099 wishlist
close 32099
stop

Hello Kingsley,

On 09/07/18 10:29 PM, Kingsley G. Morse Jr. wrote:
> And I like your benchmarks.
> 
> Mine are humbly attached.
> 
> They compare sorting to hashing.
> 
> At the moment, hashing seems to me to be about 70%
> faster.
> 
> And to scale better.
> 
> I'd still like uniq to be faster and free from
> sort.

Thank you for taking the time to create and provide these,
including the scripts to reproduce it.

I've marked this item as "closed / wishlist" - but only because it
is technically not a bug report. Discussion is welcomed to continue
by replying to this thread.

Being "faster" alone is important but not the only criteria (as
mentioned in the previous email's examples).

Your measurements are a good start towards stronger support to
hash-based uniq implementation (a working patch, btw, would be even
stronger).

I would suggest several improvements to the measurements, to ensure
relevant information is conveyed:

1.
Specify exactly which versions of awk/sort you are using
(e.g. which versions, whether from your distribution or compiled from 
source, if compiled than which compiler / optimization flags).
What CPUs is being used, how much memory does the computer have, etc.

2.
I would suggest adding "sort | uniq" to the charts, because that is the
real base-line you are trying to improve.
I would also consider adding "datamash rmdup" to the charts, because its
hash-based implementation could serve as a ball-park indication of how
a naive hash implementation would work in uniq.

3.
You input is very small (up to 90K lines of 10 characters each) - that
does not seem to stress-test any significant parts of the algorithms
(and for a typical user, waiting 0.05 seconds vs 0.15 seconds does not
matter).

I would recommend much larger input files, with much longer lines -
trying to simulate various real-world scenarios.

Here's a project of someone who tried to compare various hashing
functions: https://github.com/jhunt/hash/
Under the "corpus" directory you'll find few demo data files.
Even the largest one (qnames) is only 84MB - not very big.

Perhaps consider duplicating the content few times, then test it:
   for i in $(seq 1 5);do cat qnames; done > input

To get even closer to real-world input, try several input files
with different ratios of duplicated lines (your script create completely
random data - not very similar to real-world input files).

For example, what happens with many lines share similar sub-strings?
depending on the hashing implementation, this could lead to lower 
performance.

4.
It would be beneficial to see what's the memory requirements and limits
of a hash-based implementation. Currently, because 'sort' is not limited
by available RAM, there is no memory limit (though resorting to disk I/O
might make everything slow).
For example, is it possible to hash an 800M file on a machine with only 
1GB of RAM ? and without additional code, hashing files larger than 
available memory is simply not possible - a very big disadvantage.

5.
To compare "sort' fairly against other options,
I would add to the measurements using "--parallel 1" and later 
"--parallel N" (N being the number of cpu/cores you have).
Does that improve performance?

The "awk" (or datamash) programs do not have a built-in memory limit,
while sort does. It would be useful to specify a large amount of
memory for sort (using "-S") to ensure sort did not revert to disk I/O.

6.
The reported time in your script is the elapsed time (aka "wall time").
A more relevant option would be "user time" + "kernel time"
(optiosn %S and %U in "time -f") - the wall time can be affected by
factors that don't immediately relate to hashing/sorting performance.

7.
In your script you are providing a file-based input,
it might be useful to clear the kernel's cache before each run
to ensure these do not affect the results (especially when dealing with 
large files).
See: 
https://www.tecmint.com/clear-ram-memory-cache-buffer-and-swap-space-on-linux/




To conclude,
There is definitely merit in trying to optimize uniq's performance,
but it must be weighed against other factors (e.g. the ability to 'uniq'
a file larger than available memory, and the ease of using existing 
programs to achieve the same effect).

IMHO it is not a top-priority, so I don't want to give the impression
that if an amazing speed improvement is presented, uniq will be swiftly
rewritten.

But of course, a working patch and strong pro arguments would go a long
way towards incorporating this feature.

regards,
  - assaf







Information forwarded to bug-coreutils@HIDDEN:
bug#32099; Package coreutils. Full text available.

Message received at 32099 <at> debbugs.gnu.org:


Received: (at 32099) by debbugs.gnu.org; 10 Jul 2018 04:30:13 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Tue Jul 10 00:30:13 2018
Received: from localhost ([127.0.0.1]:52945 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1fckI1-0003op-E4
	for submit <at> debbugs.gnu.org; Tue, 10 Jul 2018 00:30:13 -0400
Received: from outbound-smtp27.blacknight.com ([81.17.249.195]:57107)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <kingsley@HIDDEN>) id 1fckHx-0003nj-4n
 for 32099 <at> debbugs.gnu.org; Tue, 10 Jul 2018 00:30:10 -0400
Received: from mail.blacknight.com (pemlinmail05.blacknight.ie [81.17.254.26])
 by outbound-smtp27.blacknight.com (Postfix) with ESMTPS id D76E8B8899
 for <32099 <at> debbugs.gnu.org>; Tue, 10 Jul 2018 05:30:02 +0100 (IST)
Received: (qmail 15376 invoked from network); 10 Jul 2018 04:30:02 -0000
Received: from unknown (HELO debian1.loaner.com)
 (kingsley@HIDDEN@[97.113.25.140])
 by 81.17.254.9 with ESMTPSA (AES256-SHA encrypted, authenticated);
 10 Jul 2018 04:30:01 -0000
Received: from kingsley by debian1.loaner.com with local (Exim 4.90_1)
 (envelope-from <kingsley@HIDDEN>)
 id 1fckHh-0001sI-Di; Mon, 09 Jul 2018 21:29:53 -0700
Date: Mon, 9 Jul 2018 21:29:53 -0700
From: "Kingsley G. Morse Jr." <kingsley@HIDDEN>
To: Assaf Gordon <assafgordon@HIDDEN>
Subject: Benchmarks: Hashing ~70% faster (Was: New uniq option for speed)
Message-ID: <20180710042953.2w46nfztrxrg6gmi@HIDDEN>
References: <20180708210356.c5fwiocbvdndkgxh@HIDDEN>
 <a499a8ae-df6d-8342-8d89-e105f6b2bc62@HIDDEN>
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="qzkemyanjw2idojc"
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
In-Reply-To: <a499a8ae-df6d-8342-8d89-e105f6b2bc62@HIDDEN>
User-Agent: NeoMutt/20170306 (1.8.0)
X-Debbugs-Envelope-To: 32099
Cc: 32099 <at> debbugs.gnu.org, Paul Eggert <eggert@HIDDEN>
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>


--qzkemyanjw2idojc
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline
Content-Transfer-Encoding: 8bit

Hi Assaf,

I like datamash.

And I like avoiding a pipe with sort's "-u"
option.

And I like your benchmarks.

Mine are humbly attached.

They compare sorting to hashing.

At the moment, hashing seems to me to be about 70%
faster.

And to scale better.

I'd still like uniq to be faster and free from
sort.

Feel free to let me know if I screwed up.

Thanks,
Kingsley

On 07/09/2018 14:53, Assaf Gordon wrote:
> Ηello,
> 
> On 08/07/18 03:03 PM, Kingsley G. Morse Jr. wrote:
> > The main reason I'm writing is to humbly suggest
> > a performance improvement to the "uniq" command.
> > 
> > It currently requires its input to be sorted.
> > 
> > Sorting generally takes about O(N*log(N)) time.
> > 
> > However, it seems to me that sorting is
> > unnecessary.
> > 
> > You can see this is so in the following example
> > 
> >      $ echo -e "b\na\nb" | awk '!seen[$0]++'
> 
> In addition to Paul's reply, here are couple of more practical issues:
> 
> 1.
> GNU sort has several non trivial (and not obvious) advantages:
> 
> It can sort a file larger than available memory (i.e. you
> can sort a 3GB file on machine with 1GB of RAM).
> 
> It can sort using multiple threads, making sorting faster.
> 
> If you have a powerful machine (lots of ram and lots of CPUs),
> you can sort entirely in memory like so:
> 
>     sort -S 10GB --parallel=10 -T /foo/bar INPUT > OUTPUT
> 
> The "-S" sets the maximum amount of memory sort is allowed to use,
> The "--parallel" sets the number of parallel sorting threads,
> The "-T" points to a non-existing directory - ensuring that
> if sort runs out of memory (input too large) then it will fail
> instead of resorting to using disk storage (and slower I/O).
> 
> There are many other combinations (e.g. "--compress-program").
> 
> A simple hash implementation will not be able to do so.
> 
> 
> 2.
> Sort already supports printing only unique values with the "-u" option.
> So by using the correct combination of keys (-k) and unique (-u)
> you can get unique values without even invoking "uniq"
> (if your concert is starting another process).
> 
> Note that uniq will compare the entire line, and sort will "unique"
> only the specified "keys", but sort also has last the "--stable"
> option that can affect the results.
> 
> 
> 3.
> Sometimes you really just want to see the list of unique values,
> and that's valid.
> But often times you want to later examine or do something with the list
> of unique values, and then it is common to sort it.
> 
> A hash implementation of "unique" will not print sorted items,
> and then you'll likely need to pipe it to another "sort" anyhow
> (perhaps with much smaller number of items, but still need sort).
> 
> 
> 4.
> The Unix philosophy often says
>   "Write programs that do one thing and do it well."
> ( https://en.wikipedia.org/wiki/Unix_philosophy )
> 
> GNU Sort does sorting very well.
> Other programs that require sorted input can rely on it (e.g. join,
> uniq, etc.).
> 
> 
> 5.
> Using your awk example is actually a fantastic way to achieve
> what you wanted - it fits perfectly in "do one thing and do it well".
> 
> Note that If you're using a recent Debian or Ubuntu machine,
> they have switched the default awk implementation from GNU awk (gawk)
> to "mawk". "mawk" is indeed faster in some aspects, but it seems gawk is
> much faster when it comes to hashing.
> 
> Observe the following:
> 
>   $ seq 1000000 | time -p gawk '!seen[$0]++' > /dev/null
>   real 0.40
>   user 0.35
>   sys 0.04
>   $ seq 1000000 | time -p mawk '!seen[$0]++' > /dev/null
>   real 10.48
>   user 10.40
>   sys 0.07
> 
> Using awk will also enable you to later extend your task to
> achieve more. Eg. the following program:
>   awk 'NR==FNR{seen[$1]++;next} seen[$1]>0' a.txt b.txt
> 
> Will only print lines from "b.txt" which have a key matching from
> file "a.txt". kind of a hash-based join between two files.
> 
> 
> 6.
> Lastly, if you still want a program that uses hashing to discard
> duplicates in a file, may I humbly suggest GNU datamash:
>    https://www.gnu.org/software/datamash/
> (disclaimer: I'm datamash's developer).
> 
> It can easily remove duplicates, and it uses the same hashing code
> that other coreutils program use. Example:
> 
>   $ printf "%s\n" a a b a b c b | datamash rmdup 1
>   a
>   b
>   c
> 
> Datamash has several additional useful features,
> for example it can remove duplicates from a specific column but still print
> the entire matching line:
> 
>   $ printf "FOO %s %s\n" a 1 a 2 b 3 a 4 b 5 c 6 b 7 \
>         | datamash -W rmdup 2
>   FOO a 1
>   FOO b 3
>   FOO c 6
> 
> 
> 
> Hope this helps,
> regards,
>  - assaf
> 

-- 
Time is the fire in which we all burn.


--qzkemyanjw2idojc
Content-Type: image/png
Content-Disposition: attachment; filename="hash_v_sort_benchmarks.1.png"
Content-Transfer-Encoding: base64

iVBORw0KGgoAAAANSUhEUgAABAMAAAJoCAYAAAATXSiNAAAABHNCSVQICAgIfAhkiAAAIABJ
REFUeJzs3Xm8HEW99/HPSUISIIQQ9mBMkIgGAsgmAZHFjYiocNkvCKhc5cENEFBZ5KBschFR
dhWILAroZYkbiktUuBIui+wkLLJDJCF7SEJy6vnjN2Mmfbqre3p6m5nve171Ss50d3V1d3V1
T3VVdQ+wABiGiIiIiIiIiHSDhT2AKzsVIiIiIiIiIlKcAWUnQERERERERESKpcoAERERERER
kS6jygARERERERGRLqPKABEREREREZEuo8oAERERERERkS6jygARERERERGRLqPKABERERER
EZEuo8oAERERERERkS6jygARERERERGRLqPKABEREREREZEuo8oAERERERERkS6jygARERER
ERGRLqPKABEREREREZEuo8oAERERERERkS6jygARERERERGRLqPKAJFu1Qu4iHBPB61TRKRq
BgJ7Az8CHgBeB5YSXjaeVVtmScR0BxxVXNJzN4jo7XTAvuUlre31omuwiKxClQFSTRPw3wzc
2GR898XENzSTVIuIiPhtAzwI/Bo4GtgWWA8YXGaiRESkG6kyQERERPL1KNGVsSeWmK6ivQv4
M7BV2QkRERFRZYCIiIhIMS4G1ik7ESIiImZQ2QkQERER6XibAh+OmedR4CVgRcN3T+aWIhER
6XKqDBCR4swCpkdMe67AdIiIFG33mOn7A7d4pk8HhkRMm5cqRdJtdA0WkQBVBohIcS6pBRGR
bvM2z7RX8FcEgA08KNIKXYNFJEBjBoiIiIjkbbhn2muFpUJEROTf1DJApFnDgXHAKGCj2t9D
gR5gQS28BDxCdjd4Q4F3YyNRrw+sCawGvAnMB14GXgCewt5VnYdhwPuBtwMjgTnA08Bd2Puv
qyav9A7BmvuOBdbF3g/+IvA3YHEL8eah6HyzFvBe7NwYiR2DucBs4DFWjiifpTLWGWZL7Mnt
aOAtYAYwFVgYs9wmrMynYPnpQeAhWkt3FcqMsowEdsTK55HA6lgz+jeAZ7D9+1YJ6fI9fiki
jyaVZ9m5GzZ2Qr3sfAH4a4vxdosqXoPDjmlVr4dZqMr1RiRjvrevKyiUEybgvJ8bm4zvvpj4
hnqWXR/Ht3DcgePVmHiCn5dwXIBjfMr9MAnHFByLE65vOY7pOK7H8QUc63ni7vXEc0/DfJvh
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
WfnpCk8ct+WwncGwDv7z1/dZHDO9SuV41vm67O1QUCggqJuAVFOS1wSCNcXyvd866CJsEKNm
/ZHkLRCqbgXWTO7ODOJ6CzgW+HmCeY+n+dcozqH5/opZ+yYwI6e4Z2BPbLJS1rHNcju65Rzt
lu1slcqrfGVdBmUlr3K3rPxUtjnYdi9scrkVRL/Fyafs8i2rfF32dogUQJUBUk2TsaZqcZot
bN/EmnE1U7j/EuvXuLzJdVXZImw/nILtkzRmALuS/Bg8hN0oJ73BrsefVxP9OEuwZpPn5rye
Y7H3cmeljGML2W1Ht5yj3bKdWVB5la+sy6BWFFHullVGlu1ubLt9A2Q2Woi93jFqHCefKpRv
WeTrKmyHSM5UGSDVNAd7XaDP3cCjKeJ+CRsR+mz8ryN8COtj90lgcYr1VF0fdsM1GjgdeAJr
MOTzJjZi8v7Y+6GTDNzY6GbsdTu+UZdfxJ4KbYv1NU3jEuAQ4HLs5jxJxVLdDKxf6WbA91Ou
vxmLsSc2O2Ppvhe7WVvaQpxlHNsst6NbztFu2c4sdHJ5Vbaszt12KnfLyE9VcDfwLuAyokfc
X4wNiLkN6SoC6sou37LK12Vvh0jOeogv/kQ612BgJ2BLYCRWE/4qVqjn1TS8ytbFLnobAetg
owvPwypnngHuJ/rVj83aGHg/9i7fodjovzOAv5N9qTQQez/4GGATbKCf1bHq0EXYCNP/BJ4E
Xsl43VVR5LHNUreco92ynVnq1PKqU7RbuduuZWRaQ7C3YozFypzZWOXWX2mu+2USnVK+dcp2
iDRQZYCIiIiIiIhIl1E3AREREREREZEuo8oAERERERERkS6jygARERERERGRLqPKABERERER
EZEuo8oAERERERERkS6jygARERERERGRLqPKABEREREREZEuo8oAERERERERkS6jygARERER
ERGRLqPKABEREREREZEuo8oAERERERERkS6jygARERERERGRLqPKABEREREREZEuo8oAERER
ERERkS6jygARERERERGRLqPKABEREREREZEuo8oAERERERERkS6jygARERERERGRLqPKABER
EREREZEuo8oAERERERERkS6jygARERERERGRLqPKABEREREREZEuo8oAERERERERkS6jygAR
ERERERGRLqPKABGRLLwGuIbw9XKT03WqvP8PBn4PzATeYtV0blRiukQkf1Uum0Sk66kyQKSd
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
n8r00L+tz53YIE3NjBcQNBBrJh/sdwjWNL3xicX5hPc/rQ8SdQfNvZKvaBdgTzei3AR8q4W4
v4g142w0EHsSNjDw/Zv4j1szx6WI9GVx7C/GnmKFjVAvqzoL+DrhfYSDrsTGmqiyudjgl4/E
zLcIa8J+S4p1PIo9cW1GO+znLPZdHvv/HGwE+qXYee0C0+fXvq/v20uBp1jZReEVrKVbMy6j
/+sfG30P+FWTcRbhi/TvKtXoxyRvkZbVPsj6miUilaTKAJF29BbWn3o3rHnns8Bi7KL9PHbT
8HHsne/B0b/jXAkcDlyCvbf+WeymbUXt30ewG5NdgeMDyy6qpakXewXZstoy9wJfwF4RVeWb
haVY5cmxwP9hA4EtxPbDkdg7sZP8KIhyKdak/zTsxm8mto+W1f7/99o8BwDrs+qxa+W4FJG+
rI79j7Am218D/oAN1rgUOw7PYj/mvsTKAcbyEGz2HRxMqyq+gw3Cdh62n9/A8uc87IfvZVg/
42PwD0hYFS9gY6B8GqvMehXLR3OxZsjnYk36b2hhHQdh3aoewcrMJNphP2ex77Lc/zti5z3A
2fR/bWXdz7Fy45fYfn0LGyj1cmAHmn+rxjJsnI+zautcVov3N9iYJSfQv1KiChZhfe6/jO3r
N7H89VdsENb/Inm6s9wHrVwTRKQt9FDNYlFEJH+vseorlr6B3fBLd/sD8MHa/x02HkNwMDkR
kSL9GPhsw9/T6D84oIhIk9QyQEREpG4oK9+HDvbUVxUBIiIi0oFUGSAiIlL3fla+tvCfWHcF
ERERkQ6kygAREZG6D9f+dViTXA1mKCIiIh1KlQEiIiJ1J7PyzRy+0b1FRERE2pwGEBQRERER
ERHpMmoZICIiIiIiItJlVBkgIiIiIiIi0mVUGSAiIiIiIiLSZVQZICIiIiIiItJlVBkgIiIi
IiIi0mVUGSAiIiIiIiLSZVQZICIiIiIiItJlVBkgIiIiIiIi0mVUGSAiIiIiIiLSZVQZICIi
IiIiItJlVBkgIiIiIiIi0mVUGSAiIiIiIiLSZVQZICIiIiIiItJlVBkgIiIiIiIi0mXatzJg
OHAJ8CqwBHgQOLCJ5bcFbgX+CSwGZgN/B47IYV0iIiIiIiIiFdKelQE9wC+BI4Fzgf2A6cDN
wMEJ43h77d/Lgc8BpwHLgJ8A38p4XSIiIiIiIiIV0gO4shPRtP8A/gc4Griq9l0PMA3YCBgL
9KWIdyDwMLA+sEHO6xIREREREREpSXu2DNgPe4r/04bvHHAtMBrYIWW8K4BXgOUFrEtERERE
RESkJO1ZGTABeAZ4M/D9Iw3TkxoCDMN+2B8PfAA4L6d1iYiIiIiIiFTAoLITkMq6wAsh37/R
MD2pq4DDav9/CzgR+EFO6xIRERERERGpgPasDMjSt4ArsDEC9gMuBNYEzmox3iQjMfS0uA4R
ERERERGRFNqzMmA2MDLk+5EN05OaUQsAt9T+7cVaDLzawrrifui337CNIiIiIiIi0iHac8yA
R4BxwBqB77eu/ftoC3Hfi71V4B0FrEtERERERESkBO1ZGXArsBor+/qDbckRwIvAfQniGBjy
3QBgH+yp/bMZrktERERERESkQtqzm8BtwF+B7wFrAU9hP853AA4B+hrmnQj8HTgTa/5fdwsw
H/gH8DqwIXAA8N5avK+mWJeIiIiIiIhIG2jPygAHfAI4BzgZGAE8CRwM3JwwjtuwH/Ufwfr/
LwQeBo4Erst4XSIiIiIiIiIV0oOGsiuHQ28TEBERERERkVK055gBItI1Dj/8cJxzOOeYNGlS
2clpWZbbs8cee/w7rsMPPzyjFHa2LPdZp+XNImnfdZbe3t5/H8/GcMEFFySO45JLLuHpp5/O
MZXRJkyYEJr+5557rpT0iIgURZUBIiIi0nF22GGHf/+omzhxYuR8V1xxxb/n22effQpMYWda
sWLFKqEow4YN46STTuKee+5h1qxZLFmyhOeee47rr7+e3Xff3busc66UNJcp6fkhIp1NlQEi
IiI1++yzz79vkA855JCykyPSdsaNG8egQYMYNGgQX/va1wpZ53ve8x4eeeQRzj//fHbaaSfW
XXddhgwZwpgxYzjssMOYOnUqF198MT094f0zH3vssX+nedCgQdx9992FpFtEpGztOYCgiIjw
j3/8gz333BOAJ554ouTUtAftM5HOMnr0aH7729+y0UYbATBlyhRuuOEG5s6dyzbbbMNxxx3H
qFGj+OIXv8iiRYv4+te/XnKKRUSqQ5UBIiJtau7cuUydOrXsZLQV7TORath444350pe+xF57
7cW4ceNYa6216OnpYf78+cyaNYuXX36Z+++/nz/96U9MmTIlMp7vfOc7/64IOOusszj99NP/
Pe33v/89119/PdOmTWP06NGcdNJJ3HDDDTzyyCO5bttLL73EoEGDOPnkk7n22mvbdh0i8v/Z
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
G7XJ6soc8/709vTC9oXAx0vXvvfOIVrP3wx8igjG87YD3g0cmP78ZzQfy39Cetss4C06l/au
x3icB2wkVjDIr06wLfB56udPgLFd19HeLxPlvSJJ6gs9X9/QYrFYLJa+KV8n1mq/j4TzSfgq
CR8q7PNOEp5J97uWhAtJuDv9eQWN69ePdswDifXrExLuSPe5koQtJHwu3f5gbv/p6bZft/G8
Wv2fVtvnpduva3G8j6WPf6yw/XASVqWPLSfhMhK+RcJNJKxNtx+f7vsgCVtJ+CUJ3yDhAhJu
Tfd5goSDSz63dq/H5eljxe1lyunp/30mfW7nk/B7EtakzzMh4a2M7bqWeb+M9ZgWi8VisTSW
nlfAYrFYLJb+KbNIOIeEZdQCzG832e8IEi4hYTUJm0l4iIR/J2GvMR7zRST8gAik15PwCxI+
kD42SMkASNiDhM+mx1xPwjoisP0OCX9Mwox0v5NJOJeE35LweLrfXSR8iYR92rxu7VyP8SQD
IOFEIrmxkUgCXEzCftSC8bfm9m3nupZ9v4zlmBaLxWKxFMqk9I4kSZIkSRoSzhkgSZIkSdKQ
MRkgSZIkSdKQMRkgSZIkSdKQMRkgSZIkSdKQMRkgSZIkSdKQMRkgSZIkSdKQMRkgSZIkSdKQ
MRkgSZIkSdKQMRkgSZIkSdKQMRkgSZIkSdKQMRkgSZIkSdKQMRkgSZIkSdKQMRkgSZIkSdKQ
MRkgSZIkSdKQmQys63UlJEmSJElS16z7vxWue1XdkIr+AAAAAElFTkSuQmCC

--qzkemyanjw2idojc
Content-Type: image/png
Content-Disposition: attachment; filename="hash_v_sort_benchmarks.2.png"
Content-Transfer-Encoding: base64

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
3kK8YS7Cmq19Buufl/QE+TzWpPZzjeV3w/pD1kle27QoRef5uin6GB3ALtjGY4PMPUr80+Cl
2OjX+2Pvl44bgKwIdT8ustAPnIo1ET8J68f9ElY+vgDcDpyCvUHli9i2eV3MOuMGj6uCTsnD
WZmLned8ZgAPtbheld2mrPx2FXbN4nvzwLPY0/i3YH380yj6HCSSkR6q3ZhNJN4IrM/dNli/
s0XAi9iJNa9mVsOx99ROwC4KxwKvwarXFmN9Cv+JDcj3Qk5pyMJIYEdstPCxjTCAbcO52G/4
B/5X9EjxysjzdVPGMboedtG/EbBuI7752LH0BHA30a8wk3r5b+C8iGkOG4D1leKSkxnl4Xyp
7F5d0fltY+AdwCbYgIEvYdv9b2R/N9Qp14nS8VQZICIiIpLUcOA+YNuI6XcDOxeXHBERkbTU
TUBERES60wexpsvrJpy/B3tDS1RFAMD17SZKRESkGKoMEBERke60FvBVrM/wT7FBzsaEzDcS
ey/4LcAXPOubgw0yKCIiUgO9ZSdAREREpFRrYe8uPwwbN+VpYDY2uOBYbGCvEQnWcwL1e9OK
iIh0LVUGiIiIiAwahg2qulmLy30De2OLiIhITagyQERERCStecBxwIVlJ0RERKQ1GjNARERE
utO/SN+sfw7w/4CtUUWAiIjUkl4tKCIiIt1rOPbu912BnbDxATYF1sHeRb4Ce/f5fOBx4B7g
duDmxjQREZGaUmWAiIiIiIiISJdRNwERERERERGRLqPKABEREREREZEuo8oAERERERERkS6j
ygARERERERGRLqPKABEREREREZEuo8oAERERERERkS6jygARERERERGRLqPKABEREREREZEu
o8oAERERERERkS6jygARqY4+wEWE28pLloiIJNQLfBC4ELgXeBlYQXi5flJJaWzWS/R5xwEf
KS9pIiJ56y07ASIiIiLSAXYCLgW2KjshIiKShFoGiIiISOd6iOinvseVmK5Osx3wJ1QRUATl
aRHJiCoDRERERKQ95wNjyk6EiIi0Qt0ERERERCS9bYG3e6Y74EHgBWBl0/f/yDNRIiISR5UB
IlIds4HHIqY9VWA6REQkuT090waAdwJ/LigtIiKSmCoDRKQ6pjaCiIjUx3jPtLtRRYCISEVp
zAARERERSc83VsCLhaVCRERapJYBItK+0cA7gNcD44C5wOPArcCyktI0EtgD2AxYD3vX9bPA
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
wDuwdwSPwkYWnok94dURbUZiI6JPxPrIzsZubP7C6hcxvVhz2Chhg4hFKXu/jAR2xEaQHtsI
A1gFyFzgn9ho6EmfnGVpBNbvdBtsfywCXsQuLvNoLt0J1sMu0DcC1sX6Nc/H9uUTwN34824r
ys67dTQcmIQNRPc67Hh7DfaYZTHW+uif2ECeL5SUxmZF5qcqCJ4D5rDqHLA4h/g6pYzrlN8h
IomoMkBEuluWlQEiIiIiIjWhbgIiIiIiIiIiXUaVASIiIiIiIiJdRpUBIiIiIiIiIl1GlQEi
IiIiIiIiXUaVASIiIiIiIiJdRpUBIiIiIiIiIl1GlQEiIiIiIiIiXaYHcGUnQkRERERERESK
o5YBIiIiIiIiIl1GlQEiIiIiIiIiXUaVASIiIiIiIiJdRpUBIiIiIiIiIl1GlQEiIiIiIiIi
XUaVASIiIiIiIiJdRpUBIiIiIiIiIl1GlQEiIiIiIiIiXUaVASIiIiIiIiJdRpUBIiIiIiIi
Il1GlQEiIiIiIiIiXUaVASIiIiIiIiJdRpUBIiIiIiIiIl1GlQEiIiIiIiIiXUaVASIiIiIi
IiJdRpUBIiIiIiIiIl1GlQEiIi8Bril8taR0/CSQjtvaXN/BwO+BWcCrgXVv1Oa6RSQfceVR
VcqrTlJUWZl1GS8i0qbeshMgIhnZHjgS2B3YDBgNLARmAy8DDwJ3AXcC95eURinOWcDxZSei
BkYCewE7N4VNA/OcDpzURhx7NcKgecA5bawva+8FDsF++3is7FiBlR0PA78FLgYWedYxHPgE
cADwFuC1jfmfAm4CpgIvZpTeduNqZ/ki8osUq1PLyr2odrkjIpXhFBQUah6+hWMlLtFnWQXS
W7XwUmAbfbWkdPwkkI7bUq7ndTj6A+taieN5HE81wvoV2O5VCG/Gf7w4HKe1GUdfYH1PVeB3
g2NNHL9O8Psddoy8LWI9r8dxf8zyC3F8PIM0txtXu8sXkV/iyqOqlFedEIouK7Mq45OEvkBc
T1VgeysoKFQuqGWASN0dBXyt7ERIpeyMPf1stjvwtxLSItV1BrBvyPf9DG03uCFwDbAFsKTp
+7HAn4GJMXGNBi4BlgK/SpHWLOIqMq15+hEwpunvO8tKSAdQWSkiXU6VASJ11sPQioAl2AXs
w1jT13WALYFdgDcWmjopy+iQ73TDEM4Bz2BdaO5u/HslduPY6Y4I/P0c1nT+TmA9rLn8QU3T
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
1jsceABYH9gg57hERERERERESlLPlgH7YU/xr2j6zgGXAOOBnVOudyXwAtBfQFwiIiIiIiIi
JalnZcC2wBPA0sD3DzZNT2okMBq7sT8GeCdwZk5xiYiIiIiIiFRAb9kJSGU94JmQ719pmp7U
hcDHG/9/FTgO+H85xSUiIiIiIiJSAfWsDMjSN4ELsDEC9gO+C6wFnNbmepOMxNDTZhwiIiIi
IiIiKdSzMmAOMC7k+3FN05Oa2QgAv2r824e1GHixjbjibvTrN2yjiIiIiIiIdIh6jhnwIDAJ
WDPw/faNfx9qY913YG8VeEMBcYmIiIiIiIiUoJ6VAdcAa7Cqrz/YLzkMeBa4K8E6hod8NwzY
F3tq/2SGcYmIiIiIiIhUSD27CVwL/AX4HrA28A/s5nxn4GPAQNO8k4G/Aadizf8H/QpYANwH
vAxsCBwAvK2x3hdTxCUiIiIiIiJSA/WsDHDAh4BvAScAY4G/AwcDVyVcx7XYTf17sf7/i4AH
gMOBSzOOS0RERERERKRCetBQduVw6G0CIiIiIiIiUop6jhkgIh3r0EMPxTmHc44pU6aUnZy2
Zfl79tprr3+v69BDD80ohZ0ty23WaXmzSNp2naWvr+/f+7M5nH322YnXMXXqVB5//PEcUxlt
2223DU3/U089VUp6RETKosoAERERqb2dd9753zd1kydPjpzvggsu+Pd8++67b4Ep7EwrV65c
LRRh9OjRHH/88dx2223Mnj2bZcuW8dRTT3HZZZex5557xi7vnCs8zWVLenyISHdRZYCIiHSt
fffd998XyB/72MfKTo5I7UyaNIne3l56e3v5yle+knt8b37zm3nwwQc566yz2GWXXVhvvfUY
OXIkEyZM4OMf/zjTp0/n3HPPpacnui/mww8//O809/b2MmPGjNzTLSJSRfUcQFBEpAvdd999
7L333gA8+uijJaemHrTNRDrH+PHjufHGG9loo40AuP7667n88suZN28eO+ywA0cffTSbbLIJ
Rx11FIsXL+arX/1qySkWEak2VQaIiNTEvHnzmD59etnJqBVtM5Fq2HjjjfnCF77A+973PiZN
msTaa69NT08PCxYsYPbs2Tz//PPcfffd/OlPf+L6668PXce3v/3tf1cEnHbaaZx88sn/nvb7
3/+eyy67jNtvv53x48dz/PHHc/nll/Pggw/m/tuee+45ent7OeGEE7jkkktqG4eIdB9VBoiI
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
tSt9+vTh2muvZeLEicydO5dzzjmnzLFE2VY+HHPMMXzwwQf8+9//ZsCAAXTq1CkeuCooKODA
Aw/kyiuv5N1336Vly5YA8Qv60q655pr47iVDhw7l+eef5/TTT+eEE07gN7/5De+++2582dKf
//znCrdQlKTazgSCUjYtxESBeXTxxRfTqVMn9t13Xw477DAef/zxEue3bt3K9ddfz4oVKyr8
drZbt25069Yt6fm1a9cyYMCAGrM+dcuWLZx00km89tprHHbYYfTs2ZOePXuWqLN69Wp++tOf
8oc//IEOHTqwYcOGjPqcOnUqGzZsiF8ofPXVV8ydO3e7em+99RabN2+OZ1r/9NNP4xf0lbV1
61aGDRvG/fffT/PmzXnsscdKnH/jjTdKbLNX1UT5Hi+Wj9fhzTffpE+fPrzyyivssssuvPzy
y/Tr14/XXnstrfaiksnnfvjw4Sxbtow777yTRo0accYZZ3DGGWckbau8nQ2ibCvXli1bRkFB
AYWFhSU+S0EQUFBQsF2Cv/vuu4+77767zLYWLlxInz59eO6552jfvj19+/alb9++29W75557
+O1vfxvtE5GkGsiZAZJqrKVLl9K1a1duuOEGPvroI9avX8/69ev58ssveeSRRzjqqKO46aab
ym1j1KhR9O7dm+HDh8e/dfvuu+/YvHkzK1euZOrUqdxwww3su+++jB07NkfPLDe++eYbevTo
waWXXsr06dNZvXo169ev5/PPP+evf/0rP/jBD3jjjTfi3wxnegGyYcMG3n777fj9ZN8yr1mz
hpkzZ8bvp5svoNioUaP48Y9/zIsvvsiSJUvi68Crgyje46Xl63WYMmUKhYWFrFq1ip122onn
n3++zAu9XIjqc//AAw/Qrl07rr76av7973+zdOlSNm7cyMaNG1m6dCmTJ0/mz3/+M717964w
r0OUbeXS8OHD6dixI0OGDOGFF15g7ty5fP/99/HzGzZs4Msvv+SJJ57g+OOP55JLLil3ltEH
H3zAQQcdxDXXXMOMGTP49ttv2bhxI1999RWjR4+mV69eDB48uFonB5WkXAo88nAEVWAMHh4e
HhkeO+ywQ7Bhw4YgCILgwQcfzPt4PDw8sn8MGzYsKLbXXnul1ca9994bzJ07N+/PBQimTJkS
BEEQzJ8/P+9j8fDw8Mjl4cwASVLaTjvttHjyuMqsS5dUM3z55ZcEQUAQBNx+++0pPy6f39wf
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
GuifQr1LYnUlqQzdunXj4IMPLrdOr169aNCgAcB2Sf/uvDNMSlK3bl3+8Y9/lDk1vl27dtxz
zz3bPSZTixYtit/eb7/9ImmzIpMnT2bTpnC7kyuvvLLM53vooYdy++2352Q8kiTVBG4Rrdoi
mpwB/YEPUqjXjdSCBpJqpR49evC3v/2Nd999l5dffplZs2axePFiNm3axO67705hYSG/+tWv
gDCx38iRI0s8/pFHHuGnP/0pffr0oXv37nzwwQfcfvvtzJo1i3r16nHsscdy1VVXxafU//Wv
f43nJcjU3LlzWbJkCa1bt+biiy9mzpw5zJo1i40bNwKwbt26crdGTMeKFSsYPXo05513Hvvv
vz8zZszgzjvvZN68eTRt2pQTTjiBCy64gGXLlrF8+fKcBSkkSarO3CJatUmQ8REQMDSFev8g
YFME/dWEI6gCY/DwqGLH4MGDg1SsWbMmOP3008tso2HDhsEzzzxT7uO3bt0a/OUvfwnq1KlT
ZhvnnntuvG6fPn1SHv9FF12UtM/x48dn5XfWvHnz4MMPP0za75dffhkceOCBwfTp04MgCILZ
s2fn/XX28PDw8PCoysd0CIIyjulVYGweHlEe0cwMSMVOhFnUvs5Zj5KqmVGjRvGf//yH3r17
07NnT9q0acNuu+1Gw4YNWb16NZ9++imvv/46999/P8uWLSuzjXXr1nHqqadywgkncP7553P0
0Uez++67s2XLFhYvXsykSZMYOXIks2bNysr4Fy1axK9+9Su6du1KixYt4ksasuXbb7/lqKOO
4oorruD0009n3333ZevWrcyfP5+nn36au+66i9WrV2d1DJIk1SRDCXMEJC4VcIto1UQFhFGB
yktcFnAIsIzkF/r1gPZAI+AB4KK0eqxZAsre8lCSJElSXhXiFtGq+dIPBlT2Uf8DXgAuj92u
7QwGSJIkSZLyJP1lAs0Sbq8CbgaSJawuAtal3ZMkSZIkSYpQ+sGAxG/3fw28jd/4S5IkSZJU
DaS/TECZcZmAJEmSJClP6kTSytNA/xTqXRKrK0mSJElV1NXAGmBj7OfV+R2OlBXRbC3Yn5K7
CyTTjdSCBpIkSZKUB1cDt7DtW9MGsfsAf8rLiKTsiGZmQKp2ADbntEdJkiRJStnv2f4iqU6s
XKpJchcM2AnoAXydsx4lSZIkqVIaVLJcqq7SXyZQelnAIOC0cnppDzQCHki7R0mSJEnKqiLK
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

--qzkemyanjw2idojc
Content-Type: text/plain; charset=us-ascii
Content-Description: benchmarking script
Content-Disposition: attachment; filename=uniq_demo

# Tweaking these...
max_lines_of_data=100000                # The total number of lines of data to search for unique values in. Bigger values have lomger run times.
max_line_length=10                      # How many bytes are in each line that may be unique. Smaller values create fewer unique lines.

# leads to...
interval_between_lines_of_data=$(( $max_lines_of_data / 5 ))

# Report heading.
echo lines,percent unique,algorithm,time

# Benchmark with increasing lines of data...
for data_lines in $( seq 1 $interval_between_lines_of_data $max_lines_of_data ) ; do

    # Benchmark with increasing line length..
    for line_length in $( seq $max_line_length ) ; do

        # Generate a certain number of lines of random data of a certain length
        tr -cd '[[:alnum:]]' < /dev/urandom | fold -bw "$line_length" | head -n "$data_lines" > /tmp/data

        # Calculate the percentage of lines that are unique.
        number_of_unique_lines="$( sort -u /tmp/data | wc -l )"
        percent_unique="$( calc -dp "$number_of_unique_lines/$data_lines" )"

        # Benchmark sort with its unique option.
        /usr/bin/time -o /tmp/sort_time -f %e sort -u /tmp/data > /dev/null 
        echo "$data_lines,$percent_unique,sort,$( cat /tmp/sort_time )"

        # Benchmark awk hashing.
        /usr/bin/time -o /tmp/hash_time -f %e awk '!seen[$0]++' /tmp/data  > /dev/null
        echo "$data_lines,$percent_unique,hash,$( cat /tmp/hash_time )"

    done
done

--qzkemyanjw2idojc
Content-Type: application/gnumeric
Content-Description: spread sheet (gnumeric)
Content-Disposition: attachment; filename="hash_and_sort_benchmarks.gnumeric"
Content-Transfer-Encoding: base64

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
tXyehov9BGOCv3pZ2ET640+HP7n78E/gbHqF1W5JrvCGX+HN01eQ+e11i4RFkvcFGM8NlXOW
PeRsdJEMXk+Kz9JBs+xN01H5xNrUumLC7SYDaIaGF1tXwSYD/cuR6lMjw2hsyOFROdPuZujn
MkOrV3p3M/QzmaGFZ3lqhp7LVM/Q3vc3Q/M3ZFZ78sVn4kBMxY79JefiQEzGT19jNxt/gdn4
cTD8fmbjk+a+PL1udxdXvWF7YZUo6BBCXep4XhRELgnDjRYC6wq529nCa+Jn88L5u33Np14u
E5ts6/8Vmz8cX2P9bCPeKdvTsLr2SETSGmzuaSpoHdgdxw+I7fiu7UZuZIchteyO59sRjRyH
wjnqkcDnaUEYEhgXBOyQ2q5LIM3xfJ+6PvEDj9p2aEu3Ta7tiOGLUcmJtclzobhz21Xnzuvs
Zg1321l321l321nlte+2s+62s+62s67e3ueye2+3nXXT7axN7t1+1qWSz2VEPN/9rJdiN2u/
3sfqcPOP7L/ZtrPxrqDdhtbv6En3eW9ojcsS8Dfpt+tvcuCbvLjn++UEoPWPux1i35CL2+0Q
+/qvanY7xNZMi+P6G5Cm8x8nv4rvE9OO75C/4Nhtkl0quXOBOxe4c4HfnAvcbZLdrKLf1xac
3SbZadlv1antNsl+P5tkX/EtrK++5U2yO7/9PPz2buvktOyz9tu7rZNb9s+BcNDf9tbJ3Ya6
5/nG67t9zaB+tH42G+qcwIkCl4auaweBG4kNdU7ghS7fKEc8P7S957mhrj679J2R9fdpJlm2
/C2SPM2afhHr9AuVP/EX7FfCIoldz/rNd4fy7E/W4KzUMF25rVdqN6jKXakqzgYAMtVwtEEt
3kotFbhyjQqctZr4dmv6exVapR1U6VUJ+GPRBhV4K5e3NUq7qK67qK672K67qK57qK57qK57
2K57qK77qK77qK772K77qK4HqK4HqK4H2K4HqK4TVNcJqusE23WC6nqI6nqI6nqI7XqI6nqE
6nqE6nqE7XqE6jpFdZ2iuk6xXaeorjvrOU+bStZD3sbFzalmPdRpd1+OdK5t21p9kHMd/5EG
z6E08qGukFIaUB73oV+luSwK2uvodUtOfNrKyLHP7rg2PHbRyIlsm9qgTLBJhea6KFBQUxc5
DmrrImdCu0OJ7wVOGLm+Y0ch9bXsBY2JjoITO7arU4OcFbV1kQMj6EKpB/V4PgwnN7Btf5MK
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

--qzkemyanjw2idojc--




Information forwarded to bug-coreutils@HIDDEN:
bug#32099; Package coreutils. Full text available.

Message received at 32099 <at> debbugs.gnu.org:


Received: (at 32099) by debbugs.gnu.org; 9 Jul 2018 20:53:15 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Jul 09 16:53:15 2018
Received: from localhost ([127.0.0.1]:52794 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1fcd9m-0003rV-N3
	for submit <at> debbugs.gnu.org; Mon, 09 Jul 2018 16:53:14 -0400
Received: from mail-pf0-f171.google.com ([209.85.192.171]:43106)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <assafgordon@HIDDEN>) id 1fcd9l-0003rF-Eg
 for 32099 <at> debbugs.gnu.org; Mon, 09 Jul 2018 16:53:13 -0400
Received: by mail-pf0-f171.google.com with SMTP id y8-v6so14477307pfm.10
 for <32099 <at> debbugs.gnu.org>; Mon, 09 Jul 2018 13:53:13 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
 h=subject:to:references:from:message-id:date:user-agent:mime-version
 :in-reply-to:content-language:content-transfer-encoding;
 bh=zOJxE1l5in9VCvy8J44BeiHu+rEFfyyxOEj10/OAUWM=;
 b=bC7ArVD7/quEVfj0knNIafWd+jiOazYrsZxAW4V2P79wUxtXNBBPpqcQVxj7qgiUnQ
 79Il2Lsj791y8toFmB/YzEBURvPsxD4jk/JeeafCHlIRlwPB2TszGhYbEA+KW3sMPwqW
 IRgu181mdTlAxRs5yzV3F44c+4UWgH/nAOpdM7fLRkio02VKgX1ow1+3eTNYP40RPzP+
 I7XH+OP8Ik5D6tTU7fzHaLhCOXkryWJ29KdaHdQPdH8VqHO1WMWkIF2bksrD2HbUOC79
 O0d/MNH9fpVUndRUtcCARiiOu8slfnxHw8Ry0m3ZwMD7JA+VZMjx9GSl+i+dsj4VQfvb
 dESw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
 d=1e100.net; s=20161025;
 h=x-gm-message-state:subject:to:references:from:message-id:date
 :user-agent:mime-version:in-reply-to:content-language
 :content-transfer-encoding;
 bh=zOJxE1l5in9VCvy8J44BeiHu+rEFfyyxOEj10/OAUWM=;
 b=bR79wMPOSkZTKOfxn5U++yMi22IrTFGUU1FFWJeqKh96/CkFA0lboY9ciI1ykE/7h8
 N6BwP9WbTIANXSmpDVWvllydf9VQVGkn/aQoKAG0bYBhFKNdo2CiDtn7vkuV+soWeRbO
 82/n3/Xu5M3kI7jGbSfH9g/oT4pKTN9Zayv8THNIR/ap11sTT4wJIMb5hT5YGgyCgdTa
 6z6x49Tg7yZfxxbBnndMI2hBmkxFYhusNQpYH+n3vbM0Zv+0DrQ49Yw/MqBrPwhybnFA
 Xxnvc15AaIfQRISmz/mDLpoKnvo7+pSKV0p9vQGVuq3CMz+HoXQfEAPlBEpGyjT+rMfX
 NDAw==
X-Gm-Message-State: APt69E1izbd5wq7r0ZjvCAEqXQ6kN9VPJm/5oPZoSszUoeoT032DkeaV
 8n3zeg9w1+bcbPmOGr0ynKrdp2Of
X-Google-Smtp-Source: AAOMgpeZ/0bqaXhuk/gUQNuBzEZdS55IBS8+t8NF8+684FEBH7c3/0zmghQUCo16jQs2bePe/RboGw==
X-Received: by 2002:a62:f909:: with SMTP id
 o9-v6mr22937773pfh.141.1531169586925; 
 Mon, 09 Jul 2018 13:53:06 -0700 (PDT)
Received: from tomato.housegordon.com (moose.housegordon.com. [184.68.105.38])
 by smtp.googlemail.com with ESMTPSA id
 q28-v6sm25388418pfg.144.2018.07.09.13.53.05
 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128);
 Mon, 09 Jul 2018 13:53:05 -0700 (PDT)
Subject: Re: bug#32099: New uniq option for speed
To: "Kingsley G. Morse Jr." <kingsley@HIDDEN>, 32099 <at> debbugs.gnu.org
References: <20180708210356.c5fwiocbvdndkgxh@HIDDEN>
From: Assaf Gordon <assafgordon@HIDDEN>
Message-ID: <a499a8ae-df6d-8342-8d89-e105f6b2bc62@HIDDEN>
Date: Mon, 9 Jul 2018 14:53:04 -0600
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
 Thunderbird/52.8.0
MIME-Version: 1.0
In-Reply-To: <20180708210356.c5fwiocbvdndkgxh@HIDDEN>
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Language: en-US
Content-Transfer-Encoding: 8bit
X-Spam-Score: 0.0 (/)
X-Debbugs-Envelope-To: 32099
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -1.0 (-)

Ηello,

On 08/07/18 03:03 PM, Kingsley G. Morse Jr. wrote:
> The main reason I'm writing is to humbly suggest
> a performance improvement to the "uniq" command.
> 
> It currently requires its input to be sorted.
> 
> Sorting generally takes about O(N*log(N)) time.
> 
> However, it seems to me that sorting is
> unnecessary.
> 
> You can see this is so in the following example
> 
>      $ echo -e "b\na\nb" | awk '!seen[$0]++'

In addition to Paul's reply, here are couple of more practical issues:

1.
GNU sort has several non trivial (and not obvious) advantages:

It can sort a file larger than available memory (i.e. you
can sort a 3GB file on machine with 1GB of RAM).

It can sort using multiple threads, making sorting faster.

If you have a powerful machine (lots of ram and lots of CPUs),
you can sort entirely in memory like so:

     sort -S 10GB --parallel=10 -T /foo/bar INPUT > OUTPUT

The "-S" sets the maximum amount of memory sort is allowed to use,
The "--parallel" sets the number of parallel sorting threads,
The "-T" points to a non-existing directory - ensuring that
if sort runs out of memory (input too large) then it will fail
instead of resorting to using disk storage (and slower I/O).

There are many other combinations (e.g. "--compress-program").

A simple hash implementation will not be able to do so.


2.
Sort already supports printing only unique values with the "-u" option.
So by using the correct combination of keys (-k) and unique (-u)
you can get unique values without even invoking "uniq"
(if your concert is starting another process).

Note that uniq will compare the entire line, and sort will "unique"
only the specified "keys", but sort also has last the "--stable"
option that can affect the results.


3.
Sometimes you really just want to see the list of unique values,
and that's valid.
But often times you want to later examine or do something with the list
of unique values, and then it is common to sort it.

A hash implementation of "unique" will not print sorted items,
and then you'll likely need to pipe it to another "sort" anyhow
(perhaps with much smaller number of items, but still need sort).


4.
The Unix philosophy often says
   "Write programs that do one thing and do it well."
( https://en.wikipedia.org/wiki/Unix_philosophy )

GNU Sort does sorting very well.
Other programs that require sorted input can rely on it (e.g. join,
uniq, etc.).


5.
Using your awk example is actually a fantastic way to achieve
what you wanted - it fits perfectly in "do one thing and do it well".

Note that If you're using a recent Debian or Ubuntu machine,
they have switched the default awk implementation from GNU awk (gawk)
to "mawk". "mawk" is indeed faster in some aspects, but it seems gawk is
much faster when it comes to hashing.

Observe the following:

   $ seq 1000000 | time -p gawk '!seen[$0]++' > /dev/null
   real 0.40
   user 0.35
   sys 0.04
   $ seq 1000000 | time -p mawk '!seen[$0]++' > /dev/null
   real 10.48
   user 10.40
   sys 0.07

Using awk will also enable you to later extend your task to
achieve more. Eg. the following program:
   awk 'NR==FNR{seen[$1]++;next} seen[$1]>0' a.txt b.txt

Will only print lines from "b.txt" which have a key matching from
file "a.txt". kind of a hash-based join between two files.


6.
Lastly, if you still want a program that uses hashing to discard
duplicates in a file, may I humbly suggest GNU datamash:
    https://www.gnu.org/software/datamash/
(disclaimer: I'm datamash's developer).

It can easily remove duplicates, and it uses the same hashing code
that other coreutils program use. Example:

   $ printf "%s\n" a a b a b c b | datamash rmdup 1
   a
   b
   c

Datamash has several additional useful features,
for example it can remove duplicates from a specific column but still 
print the entire matching line:

   $ printf "FOO %s %s\n" a 1 a 2 b 3 a 4 b 5 c 6 b 7 \
         | datamash -W rmdup 2
   FOO a 1
   FOO b 3
   FOO c 6



Hope this helps,
regards,
  - assaf





Information forwarded to bug-coreutils@HIDDEN:
bug#32099; Package coreutils. Full text available.

Message received at 32099 <at> debbugs.gnu.org:


Received: (at 32099) by debbugs.gnu.org; 9 Jul 2018 16:35:46 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Mon Jul 09 12:35:46 2018
Received: from localhost ([127.0.0.1]:52731 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1fcZ8c-0006On-Jn
	for submit <at> debbugs.gnu.org; Mon, 09 Jul 2018 12:35:46 -0400
Received: from zimbra.cs.ucla.edu ([131.179.128.68]:54520)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <eggert@HIDDEN>) id 1fcZ8a-0006Oa-Uw
 for 32099 <at> debbugs.gnu.org; Mon, 09 Jul 2018 12:35:45 -0400
Received: from localhost (localhost [127.0.0.1])
 by zimbra.cs.ucla.edu (Postfix) with ESMTP id F08BA160655;
 Mon,  9 Jul 2018 09:35:38 -0700 (PDT)
Received: from zimbra.cs.ucla.edu ([127.0.0.1])
 by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10032)
 with ESMTP id o_A58ABuek0B; Mon,  9 Jul 2018 09:35:36 -0700 (PDT)
Received: from localhost (localhost [127.0.0.1])
 by zimbra.cs.ucla.edu (Postfix) with ESMTP id BE8FF1607DC;
 Mon,  9 Jul 2018 09:35:36 -0700 (PDT)
X-Virus-Scanned: amavisd-new at zimbra.cs.ucla.edu
Received: from zimbra.cs.ucla.edu ([127.0.0.1])
 by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10026)
 with ESMTP id XXBQl52XpZO4; Mon,  9 Jul 2018 09:35:36 -0700 (PDT)
Received: from [192.168.1.9] (unknown [47.154.30.119])
 by zimbra.cs.ucla.edu (Postfix) with ESMTPSA id 7CC27160655;
 Mon,  9 Jul 2018 09:35:36 -0700 (PDT)
Subject: Re: bug#32099: New uniq option for speed
To: "Kingsley G. Morse Jr." <kingsley@HIDDEN>, 32099 <at> debbugs.gnu.org
References: <20180708210356.c5fwiocbvdndkgxh@HIDDEN>
From: Paul Eggert <eggert@HIDDEN>
Openpgp: preference=signencrypt
Autocrypt: addr=eggert@HIDDEN; prefer-encrypt=mutual; keydata=
 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
 uNcby4U=
Organization: UCLA Computer Science Department
Message-ID: <a275d0d6-02a1-32d9-9000-4a9bd8753da3@HIDDEN>
Date: Mon, 9 Jul 2018 09:35:35 -0700
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101
 Thunderbird/52.8.0
MIME-Version: 1.0
In-Reply-To: <20180708210356.c5fwiocbvdndkgxh@HIDDEN>
Content-Type: text/plain; charset=utf-8; format=flowed
Content-Language: en-US
Content-Transfer-Encoding: quoted-printable
X-Spam-Score: -2.3 (--)
X-Debbugs-Envelope-To: 32099
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -3.3 (---)

Kingsley G. Morse Jr. wrote:
>      $ echo -e "b\na\nb" | awk '!seen[$0]++'
>=20
> It basically avoids sorting by using hashed
> indexes into an associative array to find
> previously seen values in about O(N) time.

No, it's still O(N log N) because hash table lookup is really O(log N), d=
espite=20
what many textbooks say. Though no doubt we could make it faster than tha=
n the=20
sorting pipeline, it wouldn't be algorithmically faster. See, for example=
:

https://lemire.me/blog/2009/08/18/do-hash-tables-work-in-constant-time/




Information forwarded to bug-coreutils@HIDDEN:
bug#32099; Package coreutils. Full text available.

Message received at submit <at> debbugs.gnu.org:


Received: (at submit) by debbugs.gnu.org; 8 Jul 2018 22:21:27 +0000
From debbugs-submit-bounces <at> debbugs.gnu.org Sun Jul 08 18:21:26 2018
Received: from localhost ([127.0.0.1]:51528 helo=debbugs.gnu.org)
	by debbugs.gnu.org with esmtp (Exim 4.84_2)
	(envelope-from <debbugs-submit-bounces <at> debbugs.gnu.org>)
	id 1fcI3a-0006DD-NU
	for submit <at> debbugs.gnu.org; Sun, 08 Jul 2018 18:21:26 -0400
Received: from eggs.gnu.org ([208.118.235.92]:40853)
 by debbugs.gnu.org with esmtp (Exim 4.84_2)
 (envelope-from <kingsley@HIDDEN>) id 1fcGqv-0000SK-J0
 for submit <at> debbugs.gnu.org; Sun, 08 Jul 2018 17:04:18 -0400
Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)
 (envelope-from <kingsley@HIDDEN>) id 1fcGqp-0005y7-By
 for submit <at> debbugs.gnu.org; Sun, 08 Jul 2018 17:04:12 -0400
X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on eggs.gnu.org
X-Spam-Level: 
X-Spam-Status: No, score=0.8 required=5.0 tests=BAYES_50 autolearn=disabled
 version=3.3.2
Received: from lists.gnu.org ([2001:4830:134:3::11]:35868)
 by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32)
 (Exim 4.71) (envelope-from <kingsley@HIDDEN>) id 1fcGqp-0005xy-8T
 for submit <at> debbugs.gnu.org; Sun, 08 Jul 2018 17:04:11 -0400
Received: from eggs.gnu.org ([2001:4830:134:3::10]:60056)
 by lists.gnu.org with esmtp (Exim 4.71)
 (envelope-from <kingsley@HIDDEN>) id 1fcGqo-0008Bu-3D
 for bug-coreutils@HIDDEN; Sun, 08 Jul 2018 17:04:11 -0400
Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)
 (envelope-from <kingsley@HIDDEN>) id 1fcGqk-0005uU-Vs
 for bug-coreutils@HIDDEN; Sun, 08 Jul 2018 17:04:10 -0400
Received: from outbound-smtp12.blacknight.com ([46.22.139.17]:56978)
 by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32)
 (Exim 4.71) (envelope-from <kingsley@HIDDEN>) id 1fcGqk-0005ty-PG
 for bug-coreutils@HIDDEN; Sun, 08 Jul 2018 17:04:06 -0400
Received: from mail.blacknight.com (pemlinmail01.blacknight.ie [81.17.254.10])
 by outbound-smtp12.blacknight.com (Postfix) with ESMTPS id
 4CCCC1C2C39
 for <bug-coreutils@HIDDEN>; Sun,  8 Jul 2018 22:04:04 +0100 (IST)
Received: (qmail 15507 invoked from network); 8 Jul 2018 21:04:04 -0000
Received: from unknown (HELO debian1.loaner.com)
 (kingsley@HIDDEN@[97.113.25.140])
 by 81.17.254.9 with ESMTPSA (AES256-SHA encrypted, authenticated);
 8 Jul 2018 21:04:04 -0000
Received: from kingsley by debian1.loaner.com with local (Exim 4.90_1)
 (envelope-from <kingsley@HIDDEN>) id 1fcGqa-0003dq-6z
 for bug-coreutils@HIDDEN; Sun, 08 Jul 2018 14:03:56 -0700
Date: Sun, 8 Jul 2018 14:03:56 -0700
From: "Kingsley G. Morse Jr." <kingsley@HIDDEN>
To: bug-coreutils@HIDDEN
Subject: New uniq option for speed
Message-ID: <20180708210356.c5fwiocbvdndkgxh@HIDDEN>
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
User-Agent: NeoMutt/20170306 (1.8.0)
X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic]
 [fuzzy]
X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x
X-Received-From: 2001:4830:134:3::11
X-Spam-Score: -5.0 (-----)
X-Debbugs-Envelope-To: submit
X-Mailman-Approved-At: Sun, 08 Jul 2018 18:21:24 -0400
X-BeenThere: debbugs-submit <at> debbugs.gnu.org
X-Mailman-Version: 2.1.18
Precedence: list
List-Id: <debbugs-submit.debbugs.gnu.org>
List-Unsubscribe: <https://debbugs.gnu.org/cgi-bin/mailman/options/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=unsubscribe>
List-Archive: <https://debbugs.gnu.org/cgi-bin/mailman/private/debbugs-submit/>
List-Post: <mailto:debbugs-submit <at> debbugs.gnu.org>
List-Help: <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=help>
List-Subscribe: <https://debbugs.gnu.org/cgi-bin/mailman/listinfo/debbugs-submit>, 
 <mailto:debbugs-submit-request <at> debbugs.gnu.org?subject=subscribe>
Errors-To: debbugs-submit-bounces <at> debbugs.gnu.org
Sender: "Debbugs-submit" <debbugs-submit-bounces <at> debbugs.gnu.org>
X-Spam-Score: -6.0 (------)

Thank you very much for maintaining coreutils!

It seems to me that it would be hard to
underestimate how useful it is.


The main reason I'm writing is to humbly suggest
a performance improvement to the "uniq" command.

It currently requires its input to be sorted.

Sorting generally takes about O(N*log(N)) time.

However, it seems to me that sorting is
unnecessary.

You can see this is so in the following example

    $ echo -e "b\na\nb" | awk '!seen[$0]++'

It basically avoids sorting by using hashed
indexes into an associative array to find
previously seen values in about O(N) time.

I expect it would be about O(log(N)) times faster
than the sorting the uniq command currently
requires.

For big values of N, the time saved could be
substantial.


Humble suggestion.

Add an option to the "uniq" command.

Let it work quickly with unsorted data.

Maybe the new option could be something like
"-usi" for "unsorted input".

Thanks,
Kingsley

-- 
Time is the fire in which we all burn.





Acknowledgement sent to "Kingsley G. Morse Jr." <kingsley@HIDDEN>:
New bug report received and forwarded. Copy sent to bug-coreutils@HIDDEN. Full text available.
Report forwarded to bug-coreutils@HIDDEN:
bug#32099; Package coreutils. Full text available.
Please note: This is a static page, with minimal formatting, updated once a day.
Click here to see this page with the latest information and nicer formatting.
Last modified: Tue, 30 Oct 2018 09:15:01 UTC

GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997 nCipher Corporation Ltd, 1994-97 Ian Jackson.