public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Gabriel Paubert <paubert@iram.es>
To: Troy Benjegerdes <hozer@drgw.net>
Cc: linux-kernel@vger.kernel.org
Subject: Re: 64-bit divide cleanup (tested on ppc)
Date: Thu, 07 Feb 2002 17:11:33 +0100	[thread overview]
Message-ID: <3C62A735.6030906@iram.es> (raw)
In-Reply-To: <87r8oez0ks.fsf@fadata.bg> <20020127205141.L5808@mea-ext.zmailer.org> <20020128180001.G14339@altus.drgw.net>

	Hi Troy,

sorry for the delay, I was sick :-(

Troy Benjegerdes wrote:

> Attached is a patch to get rid of asm/div64.h on arches that don't have 
> optimized asm routines.
> 
> I didn't include removeing the various arch/div64.h file yet, since I want 
> some comments on this.
> 
[snipped]
> ===================================================================
> RCS file: /cvsdev/hhl-2.4.17/linux/fs/ntfs/util.c,v
> retrieving revision 1.1
> diff -u -r1.1 util.c
> --- fs/ntfs/util.c	2001/11/30 22:28:59	1.1
> +++ fs/ntfs/util.c	2002/01/29 00:40:14
> @@ -13,7 +13,8 @@
>  #include "util.h"
>  #include <linux/string.h>
>  #include <linux/errno.h>
> -#include <asm/div64.h>		/* For do_div(). */
> +#define USE_SLOW_64BIT_DIVIDES
> +#include <linux/div64.h>		/* For do_div(). */
>  #include "support.h"
>  
>  /*
> @@ -233,7 +234,7 @@
>  {
>  	/* Subtract the NTFS time offset, then convert to 1s intervals. */
>  	ntfs_time64_t t = ntutc - NTFS_TIME_OFFSET;
> -	do_div(t, 10000000);
> +	do_div(&t, 10000000);
>  	return (ntfs_time_t)t;
>  }

>  
> Index: fs/smbfs/proc.c
> ===================================================================
> RCS file: /cvsdev/hhl-2.4.17/linux/fs/smbfs/proc.c,v
> retrieving revision 1.1
> diff -u -r1.1 proc.c
> --- fs/smbfs/proc.c	2001/11/30 22:28:58	1.1
> +++ fs/smbfs/proc.c	2002/01/29 00:40:17
> @@ -18,12 +18,14 @@
>  #include <linux/dirent.h>
>  #include <linux/nls.h>
>  
> +#define USE_SLOW_64BIT_DIVIDES
> +#include <linux/div64.h>
> +
>  #include <linux/smb_fs.h>
>  #include <linux/smbno.h>
>  #include <linux/smb_mount.h>
>  
>  #include <asm/string.h>
> -#include <asm/div64.h>
>  
>  #include "smb_debug.h"
>  #include "proto.h"
> @@ -375,7 +377,7 @@
>  	/* FIXME: what about the timezone difference? */
>  	/* Subtract the NTFS time offset, then convert to 1s intervals. */
>  	u64 t = ntutc - NTFS_TIME_OFFSET;
> -	do_div(t, 10000000);
> +	do_div(&t, 10000000);
>  	return (time_t)t;
>  }


At least for these 2, your patch is wrong. 10000000 is not especially 
small and the algorithm you propose does not work for these. It is 
limited to about 65536 actually.


>  
> Index: lib/vsprintf.c
> ===================================================================
> RCS file: /cvsdev/hhl-2.4.17/linux/lib/vsprintf.c,v
> retrieving revision 1.1
> diff -u -r1.1 vsprintf.c
> --- lib/vsprintf.c	2001/11/30 22:28:59	1.1
> +++ lib/vsprintf.c	2002/01/29 00:40:24
> @@ -19,9 +19,9 @@
>  #include <linux/string.h>
>  #include <linux/ctype.h>
>  #include <linux/kernel.h>
> +/* #define USE_SLOW_64BIT_DIVIDE */
> +#include <linux/div64.h>
>  
> -#include <asm/div64.h>
> -
>  /**
>   * simple_strtoul - convert a string to an unsigned long
>   * @cp: The start of the string
> @@ -165,7 +165,7 @@
>  	if (num == 0)
>  		tmp[i++]='0';
>  	else while (num != 0)
> -		tmp[i++] = digits[do_div(num,base)];
> +		tmp[i++] = digits[do_div(&num,base)];



Forcing to use slow do_div version even when base is 8 or 16 is not 
nice. Heck I believe that seperating it into several cases and having a 
different 2 or 3 distinct loops (one for base 10, the other or 2 others
for shifts by 3 or 4) could actually result in smaller code. On PPC and 
Alpha at lesat the compiler knows how to do a divide by 10 with a 
multiply high or however it's called instruction.

Oh, and what abour removing the if and doing a do {...} while(num!=0) 
instead ?


>  	if (i > precision)
>  		precision = i;
>  	size -= precision;
> @@ -426,22 +426,31 @@
>  				}
>  				continue;
>  		}
> -		if (qualifier == 'L')
> +
> +		switch (qualifier) {
> +		case 'L':
>  			num = va_arg(args, long long);
> -		else if (qualifier == 'l') {
> -			num = va_arg(args, unsigned long);
> +			break;
> +		case 'l':
>  			if (flags & SIGN)
> -				num = (signed long) num;
> -		} else if (qualifier == 'Z') {
> +				num = (signed long long) va_arg(args, long);
> +			else
> +				num = va_arg(args, unsigned long);
> +			break;
> +		case 'Z':
>  			num = va_arg(args, size_t);
> -		} else if (qualifier == 'h') {
> -			num = (unsigned short) va_arg(args, int);
> +			break;
> +		case 'h':
>  			if (flags & SIGN)
> -				num = (signed short) num;
> -		} else {
> -			num = va_arg(args, unsigned int);
> +				num = (signed long long) va_arg(args, int);
> +			else
> +				num = va_arg(args, unsigned int);
> +			break;
> +		default:
>  			if (flags & SIGN)
> -				num = (signed int) num;
> +				num = (signed long long) va_arg(args, int);
> +			else
> +				num = va_arg(args, unsigned int);
>  		}
>  		str = number(str, end, num, base,
>  				field_width, precision, flags);
> Index: include/linux/div64.h
> ===================================================================
> RCS file: /cvsdev/hhl-2.4.17/linux/include/linux/div64.h
> diff -N div64.h
> --- /dev/null	Tue May  5 13:32:27 1998
> +++ include/linux/div64.h	Mon Jan 28 16:59:28 2002
> @@ -0,0 +1,85 @@
> +/*
> + * include/linux/div64.h
> + *
> + * Primarily used by vsprintf to divide a 64 bit int N by a small integer base

                                                                ^^^^^
Read the comments, here goes you 10000000 factor. The modulo once 
shifted left by 16 bits can easily overflow.... Perhaps you should patch
it s/small/_small_/ to better see it.



> + * We really do NOT want to encourage people to do slow 64 bit divides in
> + * the kernel, so the 'default' version of this function panics if you
> + * try and divide a 64 bit number by anything other than 8 or 16.
> + *
> + * If you really *really* need this, and are prepared to be flamed by 
> + * lkml, #define USE_SLOW_64BIT_DIVIDES before including this file.
> + */
> +#ifndef __DIV64
> +#define __DIV64
> +
> +#include <linux/config.h>
> +
> +/* configurable  */
> +#undef __USE_ASM
> +
> +
> +#ifdef __USE_ASM
> +/* yeah, this is a mess, and leaves out m68k.... */
> +# if defined(CONFIG_X86) || define(CONFIG_ARCH_S390) || defined(CONFIG_MIPS)
> +#  define __USE_ASM__
> +# endif
> +#endif
> +
> +#ifdef __USE_ASM__
> +#include <asm/div64.h>
> +#else /* __USE_ASM__ */
> +static inline int do_div(unsigned long long * n, unsigned long base)
> +{
> +	int res = 0;
> +	unsigned long long t = *n;
> +	if ( t == (unsigned long)t ){ /* this should handle 64 bit platforms */
> +		res = ((unsigned long) t) % base;
> +		t = ((unsigned long) t) / base;
> +	} else {
> +#ifndef USE_SLOW_64BIT_DIVIDES 
> +		switch (base) {
> +			case 8:
> +				res = ((unsigned long) t & 0x7);
> +				t = t >> 3;
> +				break;
> +			case 16:
> +				res = ((unsigned long) t & 0xf);
> +				t = t >> 4;
> +				break;
> +			default:
> +				panic("do_div called with 64 bit arg and unsupported base\n", base);
> +		}
> +#else /* USE_SLOW_64BIT_DIVIDES */
> +		/* this was stolen from the old asm-parisc/div64.h */
> +		/*
> +		 * Copyright (C) 1999 Hewlett-Packard Co
> +		 * Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
> +		 *
> +		 * vsprintf uses this to divide a 64-bit integer N by a small 


s/small/_small_/ just to be sure that the comment is understood.

For the 10000000 case, I believe a simple stupid looping algorithm is 
the only solution which does not result in code size explosion.

	Regards,
	Gabriel.


      reply	other threads:[~2002-02-07 16:12 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-01-25 19:34 [PATCH] 64-bit divide tweaks Momchil Velikov
2002-01-25 19:40 ` Jeff Garzik
2002-01-25 21:50   ` Tim Schmielau
2002-01-27 18:04 ` Troy Benjegerdes
2002-01-27 18:51 ` Matti Aarnio
2002-01-29  0:00   ` 64-bit divide cleanup (tested on ppc) Troy Benjegerdes
2002-02-07 16:11     ` Gabriel Paubert [this message]

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=3C62A735.6030906@iram.es \
    --to=paubert@iram.es \
    --cc=hozer@drgw.net \
    --cc=linux-kernel@vger.kernel.org \
    /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