Welcome! Log In Create A New Profile

Advanced

Floating point usage inside kernel

Posted by Nuno Santos 
Nuno Santos
Floating point usage inside kernel
November 25, 2011 12:30PM
Hi,

This question has probably bean discussed for several times in this list
but the information I found googling around is inconclusive to me.

I'm implementing a kernel input driver and I have successfully achieved
my goal for at least 75%.

Since I understand that kernel floating point usage is discouraged I
have converted most of my code to use integers. I knew that kernel
floating point usage was already discouraged in Windows but could be
done by saving floating point unit state.

However, there is a small part of my code that really needs floating
point calculations and it's conversion to integer is not being trivial.

Since that part of the code is not done intensively and since I have
already found information that leads me to believe that the same is
possible, that is, saving fpu state and successfully achieve floating
point calculation on kernel.

I found this article on the internet which deeply explains fpu usage in
kernel:

http://www.linuxsmiths.com/blog/?p=253

As a conclusion, the article says that if we need to use floating point
calculations in kernel, it is possible if we keep the state of the fpu
unit with the following calls:

*/kernel_fpu_begin()
/**/kernel_fpu_end()

We also need to use the compiler flag -mhard-float

But when I compile I get:

error: implicit declaration of function ‘kernel_fpu_begin’
[-Werror=implicit-function-declaration]
error: implicit declaration of function ‘kernel_fpu_end’
[-Werror=implicit-function-declaration]

Doing a grep -r kernel_fpu_begin * on kernel source dir I can find
several references to this functions but not them is included in the
include dir. Which include do I need to have this functions found in
compile time?

Am I even sailing in the right direction? Is this really possible or am
I wasting my time?

I'm new to kernel programming and this is not a trivial issue for me. I
hope you understand.

Thanks,

With my best regards,

Nuno Santos
/*
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Jiri Slaby
Re: Floating point usage inside kernel
November 25, 2011 01:10PM
On 11/25/2011 12:14 PM, Nuno Santos wrote:
> Doing a grep -r kernel_fpu_begin * on kernel source dir I can find
> several references to this functions but not them is included in the
> include dir. Which include do I need to have this functions found in
> compile time?

It is defined in arch specific includes. For x86 in asm/i387.h (in
arch/x86/include).

> Am I even sailing in the right direction?

You should generally not use that anyway. It's not portable and disables
preemption.

Can't you do the computations in userspace? And why it cannot be
switched to integer types -- what algorithm is that? Some math function?

reagards,
--
js
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Nuno Santos
Re: Floating point usage inside kernel
November 25, 2011 05:20PM
Hi Jiri,

Thanks for your reply.

The algorithm is a matrix transform computation to make a affine a
geometric transform.

Basicly it is based on the following functions:

http://pastebin.com/YHzYuLPU

Curiously I ran a test before writing this email and guest what.... is
working!! :)

But now that I have opened this question here I should ask... is it safe?

This is the call to the function i'm making in kernel side (most of the
computation are made in userspace during a calibration and only
calculated data goest back to kernel. Then, in runtime inside the driver
I need to call this function:

mx3d_transform(src, zone->Matrix, tex);

Which is defined in the pastebin above.

And the input data is the following:

src[0] = [0,6300]; src[1] = [0,6300]; src[2] = 1.0;
zone->Matrix (double[3][3])

u: 492.188 v: 615.234 sx: 683.158 sy: 5790.13

u: 5807.81 v: 615.234 sx: 5944.9 sy: 5900.58

u: 5807.81 v: 5684.77 sx: 6027.46 sy: 560.337

u: 492.188 v: 5684.77 sx: 751.198 sy: 476.455


and tex is output (double[3])

I'm not protecting the call to the function with kernel_fpu_begin and
kernel_fpu_end

Should I be happy with the results or should I be concerned in
converting this function only to integer?

I hope I have been clear in my language.

Thanks,

With my best regards,

Nuno

On 11/25/2011 12:08 PM, Jiri Slaby wrote:
> On 11/25/2011 12:14 PM, Nuno Santos wrote:
>> Doing a grep -r kernel_fpu_begin * on kernel source dir I can find
>> several references to this functions but not them is included in the
>> include dir. Which include do I need to have this functions found in
>> compile time?
> It is defined in arch specific includes. For x86 in asm/i387.h (in
> arch/x86/include).
>
>> Am I even sailing in the right direction?
> You should generally not use that anyway. It's not portable and disables
> preemption.
>
> Can't you do the computations in userspace? And why it cannot be
> switched to integer types -- what algorithm is that? Some math function?
>
> reagards,


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Paulo Marques
Re: Floating point usage inside kernel
November 25, 2011 06:30PM
Nuno Santos wrote:
> Hi Jiri,

Hi, Nuno

> [...]
> But now that I have opened this question here I should ask... is it safe?

No!

> [...]
> And the input data is the following:
>
> src[0] = [0,6300]; src[1] = [0,6300]; src[2] = 1.0;
> zone->Matrix (double[3][3])
>
> u: 492.188 v: 615.234 sx: 683.158 sy: 5790.13
>
> u: 5807.81 v: 615.234 sx: 5944.9 sy: 5900.58
>
> u: 5807.81 v: 5684.77 sx: 6027.46 sy: 560.337
>
> u: 492.188 v: 5684.77 sx: 751.198 sy: 476.455
>
>
> and tex is output (double[3])
[...]

Given the range of numbers you're working with, you can probably get
away with just a 16.16 fixed point representation. The operations go
like this:

convert a double to a fixed point number just do (but not on the kernel):

fixed = (s32)(double * 65536.0);

convert an integer to fixed:

fixed = integer << 16;

multiplication:

result = (s32)(((s64) fixed_a * fixed_b) >> 16);

addition:

result = fixed_a + fixed_b;

etc...

Unless you have overflow or need more than 16 bits of fractional
precision, you'll have no problem with this approach.

I hope this helps,

--
Paulo Marques - www.grupopie.com

"All generalizations are false."
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Nuno Santos
Re: Floating point usage inside kernel
November 25, 2011 06:51PM
>
> Given the range of numbers you're working with, you can probably get
> away with just a 16.16 fixed point representation. The operations go
> like this:
>
> convert a double to a fixed point number just do (but not on the kernel):
>
> fixed = (s32)(double * 65536.0);
>
> convert an integer to fixed:
>
> fixed = integer<< 16;
>
> multiplication:
>
> result = (s32)(((s64) fixed_a * fixed_b)>> 16);
>
> addition:
>
> result = fixed_a + fixed_b;
>
> etc...
>
> Unless you have overflow or need more than 16 bits of fractional
> precision, you'll have no problem with this approach.
>
> I hope this helps,
Sorry, i'm not sure if I have completely understand your suggestion. Are
you telling me to apply this transform only to my input data, or to all
the operations that are applied in the function used in kernel?

Thanks,

With my best regards,

Nuno
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Paulo Marques
Re: Floating point usage inside kernel
November 25, 2011 07:20PM
Nuno Santos wrote:
>>[...]
>> Unless you have overflow or need more than 16 bits of fractional
>> precision, you'll have no problem with this approach.
>>
>> I hope this helps,
> Sorry, i'm not sure if I have completely understand your suggestion. Are
> you telling me to apply this transform only to my input data, or to all
> the operations that are applied in the function used in kernel?

Imagine that your matrix coefficients are:

2.5, 1, 4.7
45.3, 0.765, 10
0, 0, 1

and your input is:

3420.56, 5410.76, 1

You start by converting the matrix coefficients:

2.5 * 65536.0 = 163840
.....

so the matrix becomes:

163840 65536 308019
2968781 50135 655360
0 0 65536

This can be done in userspace and the coefficients can be sent to the
kernel as fixed point numbers.

You do the same (this time on the kernel) with your input, so it becomes:

224169820 354599567 65536

Now you can do:

q[0] = fixed_mul(p[0], a[0][0]) + fixed_mul(p[1], a[1][0]) +
fixed_mul(p[2], a[2][0]);
.....

where "fixed_mul" is a function that does the multiplication as I
explained earlier.

To convert the result back to an integer, just shift down by 16.

--
Paulo Marques - www.grupopie.com

"Feed the hungry, save the whales, free the mallocs!"
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Andy Lutomirski
Re: Floating point usage inside kernel
November 28, 2011 05:11AM
On 11/25/2011 08:16 AM, Nuno Santos wrote:
> Hi Jiri,
>
> Thanks for your reply.
>
> The algorithm is a matrix transform computation to make a affine a
> geometric transform.
>
> Basicly it is based on the following functions:
>
> http://pastebin.com/YHzYuLPU
>
> Curiously I ran a test before writing this email and guest what.... is
> working!! :)
>
> But now that I have opened this question here I should ask... is it safe?

[...]

> I'm not protecting the call to the function with kernel_fpu_begin and
> kernel_fpu_end

It's not safe even if you do protect it with kernel_fpu_begin. On
x86-64, a userspace process that mucks with MXCSR can trivially cause
you to oops even if you use kernel_fpu_begin. (I'm pretty sure x86-32
has a similar issue, and I imagine that other architectures have related
issues.) This might change someday, but there are exactly zero use
cases outside staging, so don't hold your breath.

--Andy
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Nuno Santos
Re: Floating point usage inside kernel
November 28, 2011 11:20AM
Ok, understood!

Just one more question. To do this, do I need to change the data type
from double to int?

Thanks,

Nuno

On 11/25/2011 06:10 PM, Paulo Marques wrote:
> Nuno Santos wrote:
>>> [...]
>>> Unless you have overflow or need more than 16 bits of fractional
>>> precision, you'll have no problem with this approach.
>>>
>>> I hope this helps,
>> Sorry, i'm not sure if I have completely understand your suggestion. Are
>> you telling me to apply this transform only to my input data, or to all
>> the operations that are applied in the function used in kernel?
> Imagine that your matrix coefficients are:
>
> 2.5, 1, 4.7
> 45.3, 0.765, 10
> 0, 0, 1
>
> and your input is:
>
> 3420.56, 5410.76, 1
>
> You start by converting the matrix coefficients:
>
> 2.5 * 65536.0 = 163840
> ....
>
> so the matrix becomes:
>
> 163840 65536 308019
> 2968781 50135 655360
> 0 0 65536
>
> This can be done in userspace and the coefficients can be sent to the
> kernel as fixed point numbers.
>
> You do the same (this time on the kernel) with your input, so it becomes:
>
> 224169820 354599567 65536
>
> Now you can do:
>
> q[0] = fixed_mul(p[0], a[0][0]) + fixed_mul(p[1], a[1][0]) +
> fixed_mul(p[2], a[2][0]);
> ....
>
> where "fixed_mul" is a function that does the multiplication as I
> explained earlier.
>
> To convert the result back to an integer, just shift down by 16.
>

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Paulo Marques
Re: Floating point usage inside kernel
November 28, 2011 02:00PM
Nuno Santos wrote:
> Ok, understood!
>
> Just one more question. To do this, do I need to change the data type
> from double to int?

You shouldn't have any "double" declarations on kernel code or the
compiler might start using floating point instructions to handle it.

Things that the compiler can work out at compile time are probably ok,
like converting constants:

#define FIXED(a) (s32)((a) * 65536.0)

fixed = FIXED(1.25);

In this case compiler should make all the calculations at compile time
and replace the macro "FIXED(1.25)" with the integer 81920.

--
Paulo Marques - www.grupopie.com

"Don't worry, you'll be fine; I saw it work in a cartoon once..."
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Sorry, only registered users may post in this forum.

Click here to login