linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: James Bottomley <jbottomley@odin.com>
To: "vkuznets@redhat.com" <vkuznets@redhat.com>
Cc: "ulf.hansson@linaro.org" <ulf.hansson@linaro.org>,
	"linux@rasmusvillemoes.dk" <linux@rasmusvillemoes.dk>,
	"andriy.shevchenko@linux.intel.com" 
	<andriy.shevchenko@linux.intel.com>,
	"keescook@chromium.org" <keescook@chromium.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"akpm@linux-foundation.org" <akpm@linux-foundation.org>
Subject: Re: [PATCH v3 1/4] lib/string_helpers: change blk_size to u32 for string_get_size() interface
Date: Sat, 31 Oct 2015 00:21:07 +0000	[thread overview]
Message-ID: <1446250866.25009.54.camel@Odin.com> (raw)
In-Reply-To: <87d1vwskfu.fsf@vitty.brq.redhat.com>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 4205 bytes --]

On Fri, 2015-10-30 at 11:46 +0100, Vitaly Kuznetsov wrote:
> James Bottomley <jbottomley@odin.com> writes:
> 
> > On Thu, 2015-10-29 at 17:30 +0100, Vitaly Kuznetsov wrote:
> >> string_get_size() can't really handle huge block sizes, especially
> >> blk_size > U32_MAX but string_get_size() interface states the opposite.
> >> Change blk_size from u64 to u32 to reflect the reality.
> >
> > What is the actual evidence for this?  The calculation is designed to be
> > a symmetric 128 bit multiply.  When I wrote and tested it, it worked
> > fine for huge block sizes.
> 
> We have 'u32 remainder' and then we do:
> 
> exp = divisor[units] / (u32)blk_size;
> ...
> remainder = do_div(size, divisor[units]);
> remainder *= blk_size;
> 
> I'm pretty sure it will overflow for some inputs.

It shouldn't; the full code snippet does this:

        	while (blk_size >= divisor[units]) {
        		remainder = do_div(blk_size, divisor[units]);
        		i++;
        	}
        
        	exp = divisor[units] / (u32)blk_size;

So by the time it reaches the statement you complain about, blk_size is
already less than or equal to the divisor (which is 1000 or 1024) so
truncating to 32 bits is always correct.

I'm sort of getting the impression you don't quite understand the
mathematics:  i is the logarithm to the base divisor[units].  We reduce
both operands to exponents of the logarithm base (adding the two bases
together in i), which means they are by definition in a range between
zero and the base and then multiply the remaining exponents correcting
the result for a base overflow (so the result is always a correct
exponent and i is the logarithm to the base).  It's actually simply
Napier's algorithm.

The reason we're getting the up to 2.5% rounding errors you complain
about is because at each logarithm until the last one, we throw away the
remainder (it's legitimate because it's always 1000x smaller than the
exponent), but in the case of a large remainder it provides a small
correction to the final operation which we don't account for.  If you
want to make a true correction, you save the penultimate residue in each
case, multiply each by the *other* exponent add them together, divide by
the base and increment the final result by the remainder.

However, for 2.5% the physicist in me says the above is way overkill.

James

> >
> > James
> >
> >> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
> >> ---
> >>  include/linux/string_helpers.h | 2 +-
> >>  lib/string_helpers.c           | 4 ++--
> >>  2 files changed, 3 insertions(+), 3 deletions(-)
> >> 
> >> diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h
> >> index dabe643..1223e80 100644
> >> --- a/include/linux/string_helpers.h
> >> +++ b/include/linux/string_helpers.h
> >> @@ -10,7 +10,7 @@ enum string_size_units {
> >>  	STRING_UNITS_2,		/* use binary powers of 2^10 */
> >>  };
> >>  
> >> -void string_get_size(u64 size, u64 blk_size, enum string_size_units units,
> >> +void string_get_size(u64 size, u32 blk_size, enum string_size_units units,
> >>  		     char *buf, int len);
> >>  
> >>  #define UNESCAPE_SPACE		0x01
> >> diff --git a/lib/string_helpers.c b/lib/string_helpers.c
> >> index 5939f63..f6c27dc 100644
> >> --- a/lib/string_helpers.c
> >> +++ b/lib/string_helpers.c
> >> @@ -26,7 +26,7 @@
> >>   * at least 9 bytes and will always be zero terminated.
> >>   *
> >>   */
> >> -void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
> >> +void string_get_size(u64 size, u32 blk_size, const enum string_size_units units,
> >>  		     char *buf, int len)
> >>  {
> >>  	static const char *const units_10[] = {
> >> @@ -58,7 +58,7 @@ void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
> >>  		i++;
> >>  	}
> >>  
> >> -	exp = divisor[units] / (u32)blk_size;
> >> +	exp = divisor[units] / blk_size;
> >>  	/*
> >>  	 * size must be strictly greater than exp here to ensure that remainder
> >>  	 * is greater than divisor[units] coming out of the if below.
> 


ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

  reply	other threads:[~2015-10-31  0:21 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-29 16:30 [PATCH v3 0/4] lib/string_helpers: fix precision issues and introduce tests Vitaly Kuznetsov
2015-10-29 16:30 ` [PATCH v3 1/4] lib/string_helpers: change blk_size to u32 for string_get_size() interface Vitaly Kuznetsov
2015-10-29 22:27   ` James Bottomley
2015-10-29 23:19     ` Rasmus Villemoes
2015-10-29 23:24       ` Rasmus Villemoes
2015-10-30  3:33       ` James Bottomley
2015-10-30 10:46     ` Vitaly Kuznetsov
2015-10-31  0:21       ` James Bottomley [this message]
2015-11-02 15:58         ` Vitaly Kuznetsov
2015-11-03  3:40           ` James Bottomley
2015-11-03 13:13             ` Vitaly Kuznetsov
2015-11-03 17:02               ` James Bottomley
2015-11-03 20:57                 ` Rasmus Villemoes
2015-11-03 21:19                   ` James Bottomley
2015-10-29 16:30 ` [PATCH v3 2/4] lib/string_helpers.c: protect string_get_size() against blk_size=0 Vitaly Kuznetsov
2015-10-29 21:24   ` Andy Shevchenko
2015-10-29 23:00   ` James Bottomley
2015-10-29 23:32     ` Andy Shevchenko
2015-10-30  3:34       ` James Bottomley
2015-10-30 10:41         ` Vitaly Kuznetsov
2015-10-31  0:07           ` James Bottomley
2015-10-29 16:30 ` [PATCH v3 3/4] lib/string_helpers.c: don't lose precision in string_get_size() Vitaly Kuznetsov
2015-10-29 21:22   ` Andy Shevchenko
2015-10-29 16:30 ` [PATCH v3 4/4] lib/test-string_helpers.c: add string_get_size() tests Vitaly Kuznetsov
2015-10-29 21:33   ` Andy Shevchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1446250866.25009.54.camel@Odin.com \
    --to=jbottomley@odin.com \
    --cc=akpm@linux-foundation.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=keescook@chromium.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@rasmusvillemoes.dk \
    --cc=ulf.hansson@linaro.org \
    --cc=vkuznets@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).