Half word emulators and NIFs

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Half word emulators and NIFs

Paolo Negri
Dear list,

We're running some test using the half word emulator and we're seeing
few regressions.
Our application runs with no problem on 32 and 64 VMs and regressions
are specific to this emulator.
While we're still looking at shrinking the broken test in order to
identify exactly the failure, so far it seems - but we're not sure yet
- that regressions are due to some interaction with a NIF [1]
The behavior we're observing is that function clauses in pure erlang
code (code not involving NIF calls) stop matching after the invocation
of such a NIF.
So far we couldn't build very simple ad hoc test cases to reproduce
the failure, while more elaborated ones part of our application tests
are consistent and always fail (while always pass using plain 32 or 64
bit VMs).
All function clauses that we seem to "lose" are very simple matches
like integers and atoms.
What I would like to ask is

- Is it possible for a NIF to somehow break such basic features of the
VM because of the NIF non compliance with the half word machine?
- How is it possible to recognize if a NIF is or not safe to be used
with the half word emulator?

While cutting out the minimal piece of code to reproduce the failure
in order to publish it might take us some time, we're open to provide
access to an environment where is possible to consistently reproduce
the failure if someone is interested into looking into this matter.

[1] https://github.com/davisp/jiffy

Thanks in advance for your answers,

Paolo
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Half word emulators and NIFs

Sverker Eriksson
Have you tested with a debug built emulator. That may catch faulty NIF
behaviors earlier. Otherwise if a NIF builds broken terms on the process
heap it might not be discovered until later when those terms are matched
or maybe garbage collected.

There is no difference to make NIF's for the halfword emulator. Just use
the NIF API as intended and don't cheat (make assumptions about
sizeof(ERL_NIF_TERM) for example).

/Sverker, Erlang/OTP


Paolo Negri wrote:

> Dear list,
>
> We're running some test using the half word emulator and we're seeing
> few regressions.
> Our application runs with no problem on 32 and 64 VMs and regressions
> are specific to this emulator.
> While we're still looking at shrinking the broken test in order to
> identify exactly the failure, so far it seems - but we're not sure yet
> - that regressions are due to some interaction with a NIF [1]
> The behavior we're observing is that function clauses in pure erlang
> code (code not involving NIF calls) stop matching after the invocation
> of such a NIF.
> So far we couldn't build very simple ad hoc test cases to reproduce
> the failure, while more elaborated ones part of our application tests
> are consistent and always fail (while always pass using plain 32 or 64
> bit VMs).
> All function clauses that we seem to "lose" are very simple matches
> like integers and atoms.
> What I would like to ask is
>
> - Is it possible for a NIF to somehow break such basic features of the
> VM because of the NIF non compliance with the half word machine?
> - How is it possible to recognize if a NIF is or not safe to be used
> with the half word emulator?
>
> While cutting out the minimal piece of code to reproduce the failure
> in order to publish it might take us some time, we're open to provide
> access to an environment where is possible to consistently reproduce
> the failure if someone is interested into looking into this matter.
>
> [1] https://github.com/davisp/jiffy
>
> Thanks in advance for your answers,
>
> Paolo
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions
>
>  

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Half word emulators and NIFs

Paul Davis-3
On Mon, Jun 27, 2011 at 6:03 AM, Sverker Eriksson
<[hidden email]> wrote:

> Have you tested with a debug built emulator. That may catch faulty NIF
> behaviors earlier. Otherwise if a NIF builds broken terms on the process
> heap it might not be discovered until later when those terms are matched or
> maybe garbage collected.
>
> There is no difference to make NIF's for the halfword emulator. Just use the
> NIF API as intended and don't cheat (make assumptions about
> sizeof(ERL_NIF_TERM) for example).
>
> /Sverker, Erlang/OTP
>

I've reduced this to a failing test case in the NIF API [1].

In the end it boils down to these two functions (notice one is int64,
the other not):

ERL_NIF_TERM
run_test1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
    return enif_make_int64(env, 1);
}

ERL_NIF_TERM
run_test2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
    return enif_make_int(env, 1);
}

Test 1 returns a Value V where (V =:= 1) is false, but (V == 1) is
true. The second function returns a value where both comparisons are
true.

Paolo also found that amusingly this bug disappears at 2^27 as shown by:

ERL_NIF_TERM
run_test3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
    return enif_make_int64(env, 134217727);
}

ERL_NIF_TERM
run_test4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
    return enif_make_int64(env, 134217728);
}

run_test3 returns a value that can't be pattern matched against
134217727 but test 4 returns a value that can be matched against
134217728.

Also, I built R14B03 on Ubuntu 10.04 with this configure:

./configure --enable-smp --enable-threads --enable-m64-build
--without-javac --enable-halfword-emulator

The processors are a pair of dual core Xeon's if that's important at all.

[1] https://github.com/davisp/halfwordtest
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Half word emulators and NIFs

Jon Watte
FWIW, The implementation of Erlang treats integers larger than 2^27 as "bignums" which are separate from "regular integers." The reason it's not 2^31 or 2^32 is that Erlang uses a few bits for "tag bits," probably to optimize the storage of these numbers within the garbage collected heap.
 
This also means that Erlang math arithmetic is not especially zippy compared to most other languages, because the tag bits must generally be removed for each operation.
 
Chances are that making an int64 *always* generates a bignum, whereas making an int only makes a bignum if it's necessary. If the assumption is that integers < 2^27 in magnitude are always little-ints, then it seems like the behavior of making int64 is arguably broken for such numbers.
 
Sincerely,
 
jw
 


--
Americans might object: there is no way we would sacrifice our living standards for the benefit of people in the rest of the world. Nevertheless, whether we get there willingly or not, we shall soon have lower consumption rates, because our present rates are unsustainable.



On Wed, Jun 29, 2011 at 3:11 PM, Paul Davis <[hidden email]> wrote:
On Mon, Jun 27, 2011 at 6:03 AM, Sverker Eriksson
<[hidden email]> wrote:
> Have you tested with a debug built emulator. That may catch faulty NIF
> behaviors earlier. Otherwise if a NIF builds broken terms on the process
> heap it might not be discovered until later when those terms are matched or
> maybe garbage collected.
>
> There is no difference to make NIF's for the halfword emulator. Just use the
> NIF API as intended and don't cheat (make assumptions about
> sizeof(ERL_NIF_TERM) for example).
>
> /Sverker, Erlang/OTP
>

I've reduced this to a failing test case in the NIF API [1].

In the end it boils down to these two functions (notice one is int64,
the other not):

ERL_NIF_TERM
run_test1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
   return enif_make_int64(env, 1);
}

ERL_NIF_TERM
run_test2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
   return enif_make_int(env, 1);
}

Test 1 returns a Value V where (V =:= 1) is false, but (V == 1) is
true. The second function returns a value where both comparisons are
true.

Paolo also found that amusingly this bug disappears at 2^27 as shown by:

ERL_NIF_TERM
run_test3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
   return enif_make_int64(env, 134217727);
}

ERL_NIF_TERM
run_test4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
   return enif_make_int64(env, 134217728);
}

run_test3 returns a value that can't be pattern matched against
134217727 but test 4 returns a value that can be matched against
134217728.

Also, I built R14B03 on Ubuntu 10.04 with this configure:

./configure --enable-smp --enable-threads --enable-m64-build
--without-javac --enable-halfword-emulator

The processors are a pair of dual core Xeon's if that's important at all.

[1] https://github.com/davisp/halfwordtest
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Half word emulators and NIFs

Sverker Eriksson
In reply to this post by Paul Davis-3
Paul Davis wrote:

> On Mon, Jun 27, 2011 at 6:03 AM, Sverker Eriksson
> <[hidden email]> wrote:
>  
>> Have you tested with a debug built emulator. That may catch faulty NIF
>> behaviors earlier. Otherwise if a NIF builds broken terms on the process
>> heap it might not be discovered until later when those terms are matched or
>> maybe garbage collected.
>>
>> There is no difference to make NIF's for the halfword emulator. Just use the
>> NIF API as intended and don't cheat (make assumptions about
>> sizeof(ERL_NIF_TERM) for example).
>>
>> /Sverker, Erlang/OTP
>>
>>    
>
> I've reduced this to a failing test case in the NIF API [1].
>
> In the end it boils down to these two functions (notice one is int64,
> the other not):
>
> ERL_NIF_TERM
> run_test1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
> {
>     return enif_make_int64(env, 1);
> }
>
> ERL_NIF_TERM
> run_test2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
> {
>     return enif_make_int(env, 1);
> }
>
> Test 1 returns a Value V where (V =:= 1) is false, but (V == 1) is
> true. The second function returns a value where both comparisons are
> true.
>
> Paolo also found that amusingly this bug disappears at 2^27 as shown by:
>
> ERL_NIF_TERM
> run_test3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
> {
>     return enif_make_int64(env, 134217727);
> }
>
> ERL_NIF_TERM
> run_test4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
> {
>     return enif_make_int64(env, 134217728);
> }
>
> run_test3 returns a value that can't be pattern matched against
> 134217727 but test 4 returns a value that can be matched against
> 134217728.
>
> Also, I built R14B03 on Ubuntu 10.04 with this configure:
>
> ./configure --enable-smp --enable-threads --enable-m64-build
> --without-javac --enable-halfword-emulator
>
> The processors are a pair of dual core Xeon's if that's important at all.
>
> [1] https://github.com/davisp/halfwordtest
>
>  
Very nice trouble shooting. Thank you Paul.

It's a halfword-bug affecting:
enif_make_int64
enif_make_long
enif_make_uint64
enif_make_ulong

for integer values that can fit into 28 bits.

What happens is that it makes a bignum even though the value could have
fit into a small integer. Small bignums like that are not allowed internally
and that's the reason why it behaves so strangely when comparing.

I'll be back with a source patch.

/Sverker, Erlang/OTP




_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Half word emulators and NIFs

Sverker Eriksson
Sverker Eriksson wrote:

> Paul Davis wrote:
>> On Mon, Jun 27, 2011 at 6:03 AM, Sverker Eriksson
>> <[hidden email]> wrote:
>>  
>>> Have you tested with a debug built emulator. That may catch faulty NIF
>>> behaviors earlier. Otherwise if a NIF builds broken terms on the
>>> process
>>> heap it might not be discovered until later when those terms are
>>> matched or
>>> maybe garbage collected.
>>>
>>> There is no difference to make NIF's for the halfword emulator. Just
>>> use the
>>> NIF API as intended and don't cheat (make assumptions about
>>> sizeof(ERL_NIF_TERM) for example).
>>>
>>> /Sverker, Erlang/OTP
>>>
>>>    
>>
>> I've reduced this to a failing test case in the NIF API [1].
>>
>> In the end it boils down to these two functions (notice one is int64,
>> the other not):
>>
>> ERL_NIF_TERM
>> run_test1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>> {
>>     return enif_make_int64(env, 1);
>> }
>>
>> ERL_NIF_TERM
>> run_test2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>> {
>>     return enif_make_int(env, 1);
>> }
>>
>> Test 1 returns a Value V where (V =:= 1) is false, but (V == 1) is
>> true. The second function returns a value where both comparisons are
>> true.
>>
>> Paolo also found that amusingly this bug disappears at 2^27 as shown by:
>>
>> ERL_NIF_TERM
>> run_test3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>> {
>>     return enif_make_int64(env, 134217727);
>> }
>>
>> ERL_NIF_TERM
>> run_test4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>> {
>>     return enif_make_int64(env, 134217728);
>> }
>>
>> run_test3 returns a value that can't be pattern matched against
>> 134217727 but test 4 returns a value that can be matched against
>> 134217728.
>>
>> Also, I built R14B03 on Ubuntu 10.04 with this configure:
>>
>> ./configure --enable-smp --enable-threads --enable-m64-build
>> --without-javac --enable-halfword-emulator
>>
>> The processors are a pair of dual core Xeon's if that's important at
>> all.
>>
>> [1] https://github.com/davisp/halfwordtest
>>
>>  
> Very nice trouble shooting. Thank you Paul.
>
> It's a halfword-bug affecting:
> enif_make_int64
> enif_make_long
> enif_make_uint64
> enif_make_ulong
>
> for integer values that can fit into 28 bits.
>
> What happens is that it makes a bignum even though the value could have
> fit into a small integer. Small bignums like that are not allowed
> internally
> and that's the reason why it behaves so strangely when comparing.
>
> I'll be back with a source patch.
>
> /Sverker, Erlang/OTP
>
Here is a source patch. Only tested on halfword emulator.

diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 68421b4..d9b1a8e 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -833,8 +833,11 @@ ERL_NIF_TERM enif_make_uint(ErlNifEnv* env, unsigned i)

 ERL_NIF_TERM enif_make_long(ErlNifEnv* env, long i)
 {
+    if (IS_SSMALL(i)) {
+       return make_small(i);
+    }
 #if SIZEOF_LONG == ERTS_SIZEOF_ETERM
-    return IS_SSMALL(i) ? make_small(i) : small_to_big(i,
alloc_heap(env,2));
+    return small_to_big(i, alloc_heap(env,2));
 #elif SIZEOF_LONG == 8
     ensure_heap(env,3);
     return erts_sint64_to_big(i, &env->hp);
@@ -843,8 +846,11 @@ ERL_NIF_TERM enif_make_long(ErlNifEnv* env, long i)

 ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i)
 {
+    if (IS_USMALL(0,i)) {
+       return make_small(i);
+    }
 #if SIZEOF_LONG == ERTS_SIZEOF_ETERM
-    return IS_USMALL(0,i) ? make_small(i) :
uint_to_big(i,alloc_heap(env,2));
+    return uint_to_big(i,alloc_heap(env,2));
 #elif SIZEOF_LONG == 8
     ensure_heap(env,3);
     return erts_uint64_to_big(i, &env->hp);



/Sverker, Erlang/OTP

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: Half word emulators and NIFs

Paul Davis-3
On Thu, Jun 30, 2011 at 10:27 AM, Sverker Eriksson
<[hidden email]> wrote:

> Sverker Eriksson wrote:
>>
>> Paul Davis wrote:
>>>
>>> On Mon, Jun 27, 2011 at 6:03 AM, Sverker Eriksson
>>> <[hidden email]> wrote:
>>>
>>>>
>>>> Have you tested with a debug built emulator. That may catch faulty NIF
>>>> behaviors earlier. Otherwise if a NIF builds broken terms on the process
>>>> heap it might not be discovered until later when those terms are matched
>>>> or
>>>> maybe garbage collected.
>>>>
>>>> There is no difference to make NIF's for the halfword emulator. Just use
>>>> the
>>>> NIF API as intended and don't cheat (make assumptions about
>>>> sizeof(ERL_NIF_TERM) for example).
>>>>
>>>> /Sverker, Erlang/OTP
>>>>
>>>>
>>>
>>> I've reduced this to a failing test case in the NIF API [1].
>>>
>>> In the end it boils down to these two functions (notice one is int64,
>>> the other not):
>>>
>>> ERL_NIF_TERM
>>> run_test1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>>> {
>>>    return enif_make_int64(env, 1);
>>> }
>>>
>>> ERL_NIF_TERM
>>> run_test2(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>>> {
>>>    return enif_make_int(env, 1);
>>> }
>>>
>>> Test 1 returns a Value V where (V =:= 1) is false, but (V == 1) is
>>> true. The second function returns a value where both comparisons are
>>> true.
>>>
>>> Paolo also found that amusingly this bug disappears at 2^27 as shown by:
>>>
>>> ERL_NIF_TERM
>>> run_test3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>>> {
>>>    return enif_make_int64(env, 134217727);
>>> }
>>>
>>> ERL_NIF_TERM
>>> run_test4(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
>>> {
>>>    return enif_make_int64(env, 134217728);
>>> }
>>>
>>> run_test3 returns a value that can't be pattern matched against
>>> 134217727 but test 4 returns a value that can be matched against
>>> 134217728.
>>>
>>> Also, I built R14B03 on Ubuntu 10.04 with this configure:
>>>
>>> ./configure --enable-smp --enable-threads --enable-m64-build
>>> --without-javac --enable-halfword-emulator
>>>
>>> The processors are a pair of dual core Xeon's if that's important at all.
>>>
>>> [1] https://github.com/davisp/halfwordtest
>>>
>>>
>>
>> Very nice trouble shooting. Thank you Paul.
>>
>> It's a halfword-bug affecting:
>> enif_make_int64
>> enif_make_long
>> enif_make_uint64
>> enif_make_ulong
>>
>> for integer values that can fit into 28 bits.
>>
>> What happens is that it makes a bignum even though the value could have
>> fit into a small integer. Small bignums like that are not allowed
>> internally
>> and that's the reason why it behaves so strangely when comparing.
>>
>> I'll be back with a source patch.
>>
>> /Sverker, Erlang/OTP
>>
> Here is a source patch. Only tested on halfword emulator.
>
> diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
> index 68421b4..d9b1a8e 100644
> --- a/erts/emulator/beam/erl_nif.c
> +++ b/erts/emulator/beam/erl_nif.c
> @@ -833,8 +833,11 @@ ERL_NIF_TERM enif_make_uint(ErlNifEnv* env, unsigned i)
>
> ERL_NIF_TERM enif_make_long(ErlNifEnv* env, long i)
> {
> +    if (IS_SSMALL(i)) {
> +       return make_small(i);
> +    }
> #if SIZEOF_LONG == ERTS_SIZEOF_ETERM
> -    return IS_SSMALL(i) ? make_small(i) : small_to_big(i,
> alloc_heap(env,2));
> +    return small_to_big(i, alloc_heap(env,2));
> #elif SIZEOF_LONG == 8
>    ensure_heap(env,3);
>    return erts_sint64_to_big(i, &env->hp);
> @@ -843,8 +846,11 @@ ERL_NIF_TERM enif_make_long(ErlNifEnv* env, long i)
>
> ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i)
> {
> +    if (IS_USMALL(0,i)) {
> +       return make_small(i);
> +    }
> #if SIZEOF_LONG == ERTS_SIZEOF_ETERM
> -    return IS_USMALL(0,i) ? make_small(i) :
> uint_to_big(i,alloc_heap(env,2));
> +    return uint_to_big(i,alloc_heap(env,2));
> #elif SIZEOF_LONG == 8
>    ensure_heap(env,3);
>    return erts_uint64_to_big(i, &env->hp);
>
>
>
> /Sverker, Erlang/OTP
>
>

Verified that this makes my earlier tests pass.

Thanks for the quick response!

Paul Davis
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions