discuss-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Discuss-gnuradio] volk float32->int8 kernel and thus float_to_char


From: Paul Boven
Subject: Re: [Discuss-gnuradio] volk float32->int8 kernel and thus float_to_char block round or floor, depending on VOLK machine
Date: Sun, 10 Jun 2018 00:20:13 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.8.0

Hi again,

Ugh, you're right. When looking at the Volk libraries, I find:

Int: int() for generic, like rintf() with acceleration
Short: always rintf()
Char: int() for generic, like rintf() with acceleration but occasionally int().

The thing that puzzled me is that I cannot get GnuRadio to show different behaviour for the Float->Int case, whereas a small test program does show different behaviour depending on what's in .volk/volk_config.

That mystery is easily solved, because the use of Volk is commented out in the float_to_int block:

https://github.com/gnuradio/gnuradio/blob/master/gr-blocks/lib/float_to_int_impl.cc

// Disable the Volk for now. There is a problem for large 32-bit ints that
// are not properly represented by the precisions of a single float, which
// can cause wrapping from large, positive numbers to negative.
// In gri_float_to_int, the value is first promoted to a 64-bit
// value, clipped, then converted to a float.

Regards, Paul Boven.

On 06/09/2018 09:26 PM, Müller, Marcus (CEL) wrote:
Oh wait, it gets better: while the float->int16 does indeed use rintf,
float->int32 doesn't… now we don't have a majority situation pro-
rounding anymore… argh.
On Sat, 2018-06-09 at 19:24 +0000, Müller, Marcus (CEL) wrote:
Hi Paul,

I agree with everything you say. Float to char should behave
*exactly*
like float to int and short. Will fix it in that way. Will also have
a
truncating version, maybe. I've just added 3 lines of code to the
current implementation to demonstrate it's trivial to change the
rounding mode. X87 FPUs are darn mighty things.

This brings me to another aspect: As far as I can tell from this
height
is that VOLK code absolutely neglects to configure the FPU to a known
state. If the calling thread decides to do a

_MM_SET_ROUNDING_MODE(_MM_ROUND_TOWARD_ZERO);

before calling volk_32f_s32f_convert_8i, all the kernels behave like
the truncate-to-0 generic kernel. That can't be what we want, nor is
it
documented.

So, that's a bigger issue with VOLK: on one hand, we'd want to set
that
SIMD FPU control register (MXCSR) on every entry into a volk kernel
that uses rounding, under- or overflowing SIMD intrinsics to have
defined behaviour. Since we are nice programmers, we don't want to
have
surprising side effects, so we'd restore it to its original state on
exit... I see pipeline flush and performance bottleneck right there,
but it's IA64 calling convention to save and restore as callee.

Best regards,
Marcus
On Sat, 2018-06-09 at 20:18 +0200, Paul Boven wrote:
Hi Marcus,

I would prefer that when going from float to int, every 'bin'
should
have equal size. So I can think of two ways to do that:

1) zero corresponds to [-0.5 : 0.49999999]

or

2) zero corresponds to [0.0 : 0.999999]

whereas the 'generic' optimization does

3) zero corresponds to [-1 to 0.999999]

The second was actually the behaviour I was expecting, and I was
pleasantly surprised when GnuRadio seemed to do the first - but
then
occasionally it doesn't.

I just did a quick test in python3, and there, the range of int(x)
for
zero runs [-0.999999 : 0.999999], so I'm expecting most
programming
languages to behave that way.

So, I guess a programmer would expect the behaviour as in the
third
case. Someone who is converting radio signals might want either
the
first or second case, as otherwise you end up with some
interesting
non-linearities.

The gnuplot helpfile states: " The `int(x)` function returns the
integer
part of its argument, truncated toward zero."

But gnuplot also provides functions like 'floor(x)' and ceil(x).

So the real question is still, do we want the behaviour of int(x),
or
the behaviour that an analog to digital converter would have?

Finally, I'd say we want the behaviour to be the same for Int,
Short
and
Char. So I ran a few more tests.

With Volk enabled, Float to Int, Short and Char treat [-0.5 :
0.499999]
as zero, with the occasional glitch for Char.

volk_32f_s32f_convert_16i a_avx u_avx
volk_32f_s32f_convert_32i a_avx u_sse2

With these conversions for Int and Short also switched to 'generic
generic', I get the same results:

Short zero: [-0.5 : 0.499999]
Int zero:   [-0.5 : 0.499999]

So, assuming I carried out these tests correctly, the odd one out
seems
to be the generic case for float to char conversion.

Note that Volk in the 16 bit and 32 bit case uses a function
called
'rintf' in the conversions. From its manpage:

"(...) round  their argument  to  an integer value in floating-
point
format".

So I say this boils down to a bug in the 'generic' float to char
case.

This is not a fix to make lightly, because somebody is going to
have
their flowchart break because of this. Then again, in the current
situation the outcome depends on which optimizations your machine
happens to have available, so that's also quite bad.

Possibly there is also an optimization opportunity of never using
'generic' even at the block edge when acceleration is available by
choosing the right size of blocks, but that's probably a small
gain.

Regards, Paul Boven.



On 06/09/2018 07:18 PM, Müller, Marcus (CEL) wrote:
Hi Paul,

yes, this seems to be the case where the "naive" C implementation
behaves differently from all the SIMD ones:

As far as I know – but I'm desparately looking for any standards
document that specifies that – doing a

int8_t val = (int8_t) 8.8f;

will always lead to 8, whereas

int8_t val = (int8_t) -8.8f;

would always lead to -8.

Now, for the conversion operations used in the SIMD kernels, it
depends
on specific flags being set in FPU-control registers (MXCSR, it
seems).
Ummmm. Noone set these to give identical results as the native C
conversion above, so if I set the tolerance in the kernel unit
test
to
0 instead of 1 (which it always should have been), I get a whole
lot of
failures. Great.

Normally, we'd stick with the what the generic version of a
kernel
gives us.

I'd do that here, too. But: that would lead to a non-rounding
behaviour... I'm breaking someone's porcelain here, no matter
what
I
do.

Any ideas?

Best regards,
Marcus

On Sat, 2018-06-09 at 18:24 +0200, Paul Boven wrote:
Hi Marcus,

Just reran the test after editing volk_config, and the result
is
somewhat surprising:

Every float in [-1:1] now converts to zero. Every float in
[1:2]
now
converts to 1. Whereas it should be [-0.5:0.5] and [0.5:1.5].

It seems that most of the time, the u_sse2 converter is used,
but
at
the
end of each multiple of 8192 bytes, a few are done with the
'generic'
converter - that would match perfectly with the observed
behaviour.

It was also pointed out to me (on irc, unfortunately no longer
in
my
history) that it is strange that for some acceleration types,
there
is a
cast to int16_t instead of int8_t at the end of the routine,
e.g.:

https://github.com/gnuradio/volk/blob/master/kernels/volk/volk_
32
f_s3
2f_convert_8i.h#L200

I had not really looked into that before because having run the
volk_profile seemed to make no difference.

Regards, Paul Boven.

On 06/09/2018 06:08 PM, Müller, Marcus (CEL) wrote:
I can reproduce these, but do the errors disappear for you if
you
replace "u_sse2 u_sse2" with "generic generic" on that line?


Best regards,
Marcus
On Sat, 2018-06-09 at 18:04 +0200, Paul Boven wrote:
Hi Marcus,

This machine did not yet have a volk_config when I ran
these
tests.

I have since run volk_profile and rebooted, and the Float-
Char

quantization bug still occurs.

$ volk-config-info --machine
avx2_64_mmx_orc

$ grep volk_32f_s32f_convert_8i .volk/volk_config
volk_32f_s32f_convert_8i u_sse2 u_sse2

Regards, Paul Boven.

On 06/09/2018 05:30 PM, Müller, Marcus (CEL) wrote:
Hi Paul,

hm, OK, considering the actual conversion is done in
VOLK,
can
you
tell
us

* whether ~/.volk/volk_config exists (and if so, its
contents
regarding
volk_32f_s32f_convert_8i )
* what the output of `volk-config-info --machine` is?

Thanks,
Marcus

On Sat, 2018-06-09 at 17:13 +0200, Paul Boven wrote:
Hi everyone,

I'm trying to perform 2 bit sampling of an RF signal.
In
one
approach,
I'm using a float->char block, and noticed that around
zero,
a
number
of
float inputs become quantized in a bin that's one off
from
the
correct
value. The ones that are wrong are always off by one,
with
their
quantization error always in the direction of zero.

The problem can be demonstrated with a really simple
flowchart,
using
the following blocks:

* Noise Source (Noise Type: Gaussian, Amplitude: 1,
Seed:
0,
Output
type: Float)
* Throttle
The throttle is then connected to two blocks:
* A file-sink (Type Float) and a
* 'Float to Char' block.
* The float to char block is again connected to a File
Sink,
now
of
type
Char.

As an example, I've plotted all the samples that
quantized as
zero.
These should fall in the range [-0.5:0.5], but
occasionally
we
also
get
hits that lie within [-1:1]. These mishaps are rare
(about
one in
2000).
It also shows that they only occur at multiples of 8192
samples,
and
zooming in reveals that they always happen shortly
before
the
next
multiple of 8192, not after.

For other values than 0, the same applies, but the
misquantizations
are
only in one direction, ending up in a lower bin if the
input
is
positive, or in a higher bin if the input is negative.
Again,
the
misquantizations only occur in half the bin: For a
value
of
1,
the
float
value should be in [0.5:1.5], but occasionally a value
in
[1.5:2]
also
ends up being quantized as 1.

This seems to me a bug that is somehow related to
internal
block
boundaries, but I'm not familiar enough with the
internals of
GnuRadio
to figure out just what's going wrong.

The problem does NOT occur when converting to Short or
Int.

This is using GnuRadio 3.7.11 (as packaged with Ubuntu
18.04).

Regards, Paul Boven.










_______________________________________________
Discuss-gnuradio mailing list
address@hidden
https://lists.gnu.org/mailman/listinfo/discuss-gnuradio

_______________________________________________
Discuss-gnuradio mailing list
address@hidden
https://lists.gnu.org/mailman/listinfo/discuss-gnuradio




reply via email to

[Prev in Thread] Current Thread [Next in Thread]