Re: Additional memory handler features.

2015-01-04 Thread Niels Möller
Marc Glisse marc.gli...@inria.fr writes:

 Er, people have been using the custom allocators for (possibly
 imperfect) recovery on allocation failure for years. PPL's configure
 script complains if gmp was compiled without -fexceptions for that
 reason. Apparently SWI-Prolog uses longjmp
 (http://stackoverflow.com/a/14245611/1918193).

Ok, good to hear about some examples. We ought to investigate these
before deciding what to do to improve error recovery hooks.

 Although itch/scratch may force a compromise between overestimating
 the space required or spending too long estimating it, which I hope
 won't penalize small numbers too much.

I think a typical itch function will look like

  mp_size_t
  foo_itch (mp_size_t n)
  {
if (LIKELY (BELOW_THRESHOLD (n, FOO_THRESHOLD)))
  return n; /* Or possibly zero or some other constant */
else
  ... something possibly more complicated, perhaps
  a full synthetic computation ...
  }

So it's a function call (I think we usually want to avoid macros here),
but for small operands it's just the function call overhead and a
well-predicted branch.

Regards,
/Niels

-- 
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.
___
gmp-devel mailing list
gmp-devel@gmplib.org
https://gmplib.org/mailman/listinfo/gmp-devel


Re: Additional memory handler features.

2015-01-04 Thread Marc Glisse

On Sun, 4 Jan 2015, Victor Shoup wrote:


But I see mention of itching and scratching: could somebody
describe what that is or provide a link? Sorry for my ignorance.
and sorry for the length of this post


The general idea is to push all operations that may fail or otherwise
require customization to user code. There would be a function
mpn_mul_itch that would tell you how much temporary (scratch) space
mpn_mul may need, and mpn_mul would take as argument a pointer to a
buffer of at least this size. Allocation is the user's responsibility. 
There should already be a few functions or macros with itch in their 
name.



[FULL DISCLOSURE: my own, somewhat narrow and selfish goal
is to see GMP's mpn-level routines throw exceptions, rather
than abort, with no interface changes.  This is what would work
best for my own NTL library]


mpn functions have few reasons to abort. Except for allocation failure,
as long as you checked the operands before passing them to GMP...


[And yet another issue: my understanding is that some OS's actually
have rather weird ways of dealing with out-of-memory errors:
malloc always succeeds and returns a non-null pointer, but
indirecting through that pointer may abort the program.
In such a setting, all of this memory-related error handling
stuff is pointless]


Yes. Memory overcommit can often be disabled or mitigated in various
ways, but it does complicate things (get a better OS ;-)

--
Marc Glisse
___
gmp-devel mailing list
gmp-devel@gmplib.org
https://gmplib.org/mailman/listinfo/gmp-devel


Re: Additional memory handler features.

2015-01-04 Thread Niels Möller
Victor Shoup sh...@cs.nyu.edu writes:

 First, it seems to me that Marc's example of custom allocators
 can perhaps best be viewed as a work-around of GMP's lack of
 proper error handling.  So one should be careful not to
 conflate error handling with memory management.

Maybe. Nevertheless, I'll focus on the handling of allocation failures
below.

 So let's ignore custom memory allocators for a minute,
 and just think about error handling.
 There are just a few viable approaches:
   1) abort with error message (current approach)
   2) return codes (the traditional C approach)
   3) C++ exceptions
   4) longjump

My take is that (1) is a reasonable default behaviour. (2) is probably a
too big interface change (even if one realizes that applications using
default allocators, which abort on failure, doesn't need to check the
return values).

As for (3) and (4), I'd prefer to not have gmp make this choice. But
defer to the custom allocation functions (and any other exception
function pointer for other types of errors) if it wants to abort, or
longjmp, or raise some type of exception.

I think we should also keep in mind other types of exceptions than those
provided by C++, e.g., guile exceptions or objc exceptions.

I'd strongly prefer if we can define an interface for error handling and
clean up temporary storage which works fine if gmp is compiled as plain
C, and is language agnostic, e.g., based on memory pools. But if that
turns out to be too difficult, I guess it's not too unreasonable to have
proper cleanup on C++ exceptions require that gmp is compiled with a C++
compiler.

Regards,
/Niels

-- 
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.
___
gmp-devel mailing list
gmp-devel@gmplib.org
https://gmplib.org/mailman/listinfo/gmp-devel


Re: Additional memory handler features.

2015-01-04 Thread Niels Möller
Victor Shoup sh...@cs.nyu.edu writes:

 But I see mention of itching and scratching: could somebody
 describe what that is or provide a link? Sorry for my ignorance.
 and sorry for the length of this post

The idea is that instead of having gmp allocate temporary storage, it
should have a function to tell how much temporary storage is needed for
each operation, and then let the application allocate that anyway it
please, and pass it as an additional argument. So instead of

  mpn_mul (rp, ap, an, bp, bn);

one would do something like

  mp_limb_t *scratch = xalloc (sizeof(mp_limb_t) * mpn_mul_itch (an, bn));
  mpn_mul (rp, ap, bn, bp, bn, scratch);
  free (scratch);
  
For convenience, higher level functions could allow a NULL scratch
argument, and allocate temporary storage using registered gmp allocation
functions.

All this applies to mpn functions only.

There are several motivations for this type of interface:

1. For low-level mpn loops, this helps eliminate the frame pointer,
   making one more register available. (Functions using alloca need a
   frame pointer).

2. For higher-level functions, it may help reuse temporary storage,
   reducing the total storage need of GMP.

3. It should make it possible for applications to allocate temporary
   storage up front. E.g., when a cryptographic application initializes
   a key, it may allocate up front all temporary storage needed for
   operations using that key, so that later operations can never fail
   for memory allocation reasons. Even static allocation may be possible
   in some cases.

Of course there are also some drawbacks. It makes life more complicated
for applications, and the implementation of functions like mpn_mul_itch,
which interact with pretty complex algorithm choice machinery, is going
to be a bit complex too.

Regards,
/Niels

-- 
Niels Möller. PGP-encrypted email is preferred. Keyid C0B98E26.
Internet email is subject to wholesale government surveillance.
___
gmp-devel mailing list
gmp-devel@gmplib.org
https://gmplib.org/mailman/listinfo/gmp-devel


Re: Additional memory handler features.

2015-01-04 Thread David Harvey

On 5 Jan 2015, at 10:08 am, Niels Möller ni...@lysator.liu.se wrote:

 Of course there are also some drawbacks. It makes life more complicated
 for applications, and the implementation of functions like mpn_mul_itch,
 which interact with pretty complex algorithm choice machinery, is going
 to be a bit complex too.

Another downside is the additional overhead in the case of very small operands.

david

___
gmp-devel mailing list
gmp-devel@gmplib.org
https://gmplib.org/mailman/listinfo/gmp-devel


Re: Additional memory handler features.

2015-01-04 Thread Vincent Lefevre
On 2015-01-04 11:41:02 -0500, Victor Shoup wrote:
 So let's ignore custom memory allocators for a minute,
 and just think about error handling.
 There are just a few viable approaches:
   1) abort with error message (current approach)
   2) return codes (the traditional C approach)
   3) C++ exceptions
   4) longjump
 
 Approach (2) would require changes to the current interface.
 For functions that currently return void, one could just make them
 return int, and so this would be a fairly minor change.
 But there are presumably some functions that already return
 a non-void value, and so this would not work for such functions.
 Another issue is that clients would now have to constantly
 check these return codes -- failure to do so is even worse
 than approach (1).

An alternate approach to (2) would be to have objects (mpz_t, mpq_t,
mpf_t...) that can contain error values. For the usual arithmetic
operations, the clients would not really need to do any check since
error values would propagate. This would be a bit like NaN for
floating-point values (except that the error would not come from the
values of the arguments, but from limitations of the environment).
Of course, the clients would need to be careful with operations that
cannot propagate the error (comparisons, some conversions...).

-- 
Vincent Lefèvre vinc...@vinc17.net - Web: https://www.vinc17.net/
100% accessible validated (X)HTML - Blog: https://www.vinc17.net/blog/
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
___
gmp-devel mailing list
gmp-devel@gmplib.org
https://gmplib.org/mailman/listinfo/gmp-devel


Re: Additional memory handler features.

2015-01-04 Thread David M. Warme

I completely agree with Niel's assessment of Victor's options (1) - (4)
for handling errors.

Recall the following from Torbjörn's original post:


There are real scenarios where one would want different sets of
allocation functions.  E.g., many libraries use GMP.  Some of them have
their own error reporting mechanisms, and memory handles.  But then the
user might use GMP directly, or she might from the same program use
several libraries which use GMP.  The current GMP memory allocation
mechanism is not suitable here.


Correct.  Single global pointer -- bothersome to share in a multi-library
context, impossible to share in a multi-library + multi-threaded context.


[Torbjörn]
I am not too fond of these global pointers.  It would be better design
to refer the memory handling and error handling functions from each GMP
user variable, akin to object oriented languages' vtables.  Except that
this would make these small structures 3 times larger.
...
That would cost a lot in cache load for applications which e.g. use
arrays of GMP numbers.


I use large (potentially huge) arrays of GMP numbers, and would suffer
greatly from such a design choice.  This is why I entered the discussion.

This is a poor resource utilization trade-off -- i.e., making these objects
3 times larger for functionality that is executed very rarely (if at all)
in normal operation.  It is still a poor trade-off at 25% overhead,
and perhaps even at 4 bits if the main functionality suffers too much.


[Niels]
I think we should also keep in mind other types of exceptions than those
provided by C++, e.g., guile exceptions or objc exceptions.

I'd strongly prefer if we can define an interface for error handling and
clean up temporary storage which works fine if gmp is compiled as plain
C, and is language agnostic, e.g., based on memory pools. But if that
turns out to be too difficult, I guess it's not too unreasonable to have
proper cleanup on C++ exceptions require that gmp is compiled with a C++
compiler.


I agree completely.  While I do not mind compiling GMP as C++ code, I
vigorously reject the recent suggestion of migrating GMP toward a C++ only
code base.  There is too much C code out there that uses GMP, mine included.
Although it is relatively simple for C++ to call a C library, the reverse is
indescribably ugly, difficult and non-portable.


[Niels]
I'd strongly prefer if we can define an interface for error handling and
clean up temporary storage which works fine if gmp is compiled as plain
C, and is language agnostic...


Consider my dynamically scoped exception handler example -- upon further
reflection, I realize that it is possible to implement this completely
outside of GMP using only a single static function pointer that GMP invokes
to report exceptions.  This would even work in a multi-threaded context.
[The handler record resides in the application's stack frame, and the
signal raising/propagation loop resides in the application's handler
function invoked via pointer from GMP.]

The reason you would want to build it all into GMP is to address Torbjörn's
several libraries requirement.  If this is built into GMP, then every
well-behaved library that uses GMP will choose to receive exceptions using
dynamically-scoped handlers, and the handler of last resort can/should be
set by the top-level application.  This works well even in contexts that are
both multi-library and multi-threaded.

If you don't build it into GMP, there would be no standard for libraries
and applications to adhere to and each library would still fight over the
global function pointer -- and it wouldn't work at all if you add multiple
threads to the mix.

The cost of this mechanism (both in space and time) yields an efficient
utilization of resources, especially for a mechanism that is almost never
used under normal conditions.

One piece missing from my example code: a GMP longjmp cleanup function
that takes a prospective jmp_buf * as an argument.  It would perform
cleanup / popping of both the stack temporaries, and pop any intervening
handler records (while possibly delivering unwind-protect exceptions)
from the dynamic chain.  Applications could call this before doing
longjmp().  It would take care of the platform-dependent problem of
choosing how far to traverse/pop each chain (TMP_ALLOC and exception).

Details of what to pass to the handler (and how) are an independent issue.

A proposal, based on Unix/Linux signal handler interface:

- An integer code indicating the type of exception (#define's in gmp.h).

- A pointer to the struct gmp_exception_handler_record whose handler
  is being invoked (NULL when invoking the static pointer handler).
  The user can embed her gmp_exception_handler_record inside of a larger
  structure in the stack frame.  The handler can know this and use it
  to gain access to arbitrary local state -- even cleanup when handling
  unwind-protect exceptions.

- A void * pointer to info provided by the 

Re: Additional memory handler features.

2015-01-04 Thread Vincent Lefevre
On 2015-01-04 23:17:16 +, David Harvey wrote:
 On 5 Jan 2015, at 10:08 am, Niels Möller ni...@lysator.liu.se wrote:
  Of course there are also some drawbacks. It makes life more complicated
  for applications, and the implementation of functions like mpn_mul_itch,
  which interact with pretty complex algorithm choice machinery, is going
  to be a bit complex too.
 
 Another downside is the additional overhead in the case of very
 small operands.

It depends on how this is implemented. For very small arguments, the
memory could be taken from the stack and the pointer to the scratch
area could be ignored. Ideally the whole code could be inlined in
such a case, reducing even more the overhead.

-- 
Vincent Lefèvre vinc...@vinc17.net - Web: https://www.vinc17.net/
100% accessible validated (X)HTML - Blog: https://www.vinc17.net/blog/
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)
___
gmp-devel mailing list
gmp-devel@gmplib.org
https://gmplib.org/mailman/listinfo/gmp-devel