Skip to contentSkip to conversation

lib: Add strongly typed 64bit int_sqrt

PATCH Superseded Crt Mori 3 participants 7 messages Dec 18, 2017 – Dec 19, 2017

Subsystems (2)

v6 of 13 Superseded Latest is v13 →

lore
Share & tools
lore

Crt Mori

author
#0 lore raw

PATCH v6 1/3 lib: Add strongly typed 64bit int_sqrt

There is no option to perform 64bit integer sqrt on 32bit platform. Added stronger typed int_sqrt64 enables the 64bit calculations to be performed on 32bit platforms. Although int_sqrt() is a rough approximation, the same algorithm is used in int_sqrt64() as good enough on 32bit platform.

---
 include/linux/kernel.h |  1 +
 lib/int_sqrt.c         | 26 ++++++++++++++++++++++++++
 2 files changed, 27 insertions(+)
include/linux/kernel.h +1 -0
index 0ad4c3044cf9..09f53063f2c9 100644
@@ -459,6 +459,7 @@ extern int kernel_text_address(unsigned long addr);
 extern int func_ptr_is_kernel_text(void *ptr);
 
 unsigned long int_sqrt(unsigned long);
+u64 int_sqrt64(u64 x);
 
 extern void bust_spinlocks(int yes);
 extern int oops_in_progress;		/* If set, an oops, panic(), BUG() or die() is in progress */
lib/int_sqrt.c +26 -0
index 1ef4cc344977..de5836448ea3 100644
@@ -36,3 +36,29 @@ unsigned long int_sqrt(unsigned long x)
 	return y;
 }
 EXPORT_SYMBOL(int_sqrt);
+
+/**
+ * int_sqrt64 - strongly typed int_sqrt function
+ * @x: 64bit integer of which to calculate the sqrt
+ */
+u64 int_sqrt64(u64 x)
+{
+	u64 b, m, y = 0;
+
+	if (x <= 1)
+		return x;
+
+	m = 1ULL << (64 - 2);
+	while (m != 0) {
+		b = y + m;
+		y >>= 1;
+
+		if (x >= b) {
+			x -= b;
+			y += m;
+		}
+		m >>= 2;
+	}
+	return y;
+}
+EXPORT_SYMBOL(int_sqrt64);
Signature · 1 line
2.15.0
#1 lore raw
Quoted 5 lines · Crt Mori

There is no option to perform 64bit integer sqrt on 32bit platform. Added stronger typed int_sqrt64 enables the 64bit calculations to be performed on 32bit platforms. Although int_sqrt() is a rough approximation, the same algorithm is used in int_sqrt64() as good enough on 32bit platform.

[]

include/linux/kernel.h

Quoted 1 line
include/linux/kernel.h +0 -0

[]

lib/int_sqrt.c

Quoted 9 lines
include/linux/kernel.h +1 -0
@@ -459,6 +459,7 @@ extern int kernel_text_address(unsigned long addr);
 extern int func_ptr_is_kernel_text(void *ptr);
 
 unsigned long int_sqrt(unsigned long);
+u64 int_sqrt64(u64 x);
 
 extern void bust_spinlocks(int yes);
 extern int oops_in_progress;		/* If set, an oops, panic(), BUG() or die() is in progress */
lib/int_sqrt.c +0 -0

[]

Quoted 20 lines
lib/int_sqrt.c +16 -0
@@ -36,3 +36,29 @@ unsigned long int_sqrt(unsigned long x)
 	return y;
 }
 EXPORT_SYMBOL(int_sqrt);
+
+/**
+ * int_sqrt64 - strongly typed int_sqrt function
+ * @x: 64bit integer of which to calculate the sqrt
+ */
+u64 int_sqrt64(u64 x)
+{
+	u64 b, m, y = 0;
+
+	if (x <= 1)
+		return x;
+
+	m = 1ULL << (64 - 2);
+	while (m != 0) {
+		b = y + m;
+		y >>= 1;

lib/int_sqrt.c unsigned long int_sqrt(unsigned long x) · line 64

Quoted 10 lines
lib/int_sqrt.c +10 -0
+
+		if (x >= b) {
+			x -= b;
+			y += m;
+		}
+		m >>= 2;
+	}
+	return y;
+}
+EXPORT_SYMBOL(int_sqrt64);

int_sqrt is now optimized with __fls

Because u64 is unsigned long on 64 bit arches, this could probably be optimized for 64 bit distributions with something like:

#if BITS_PER_LONG != 64
#define int_sqrt64 _int_sqrt64
u64 _int_sqrt64(u64 x);
#else
#define int_sqrt64(x) int_sqrt
#endif

...

#if BITS_PER_LONG != 64
u64 _int_sqrt64(u64 x)
{ etc.. }
#endif

author
#2 lore raw
Quoted 63 lines · Joe Perches
Quoted 5 lines · Crt Mori

There is no option to perform 64bit integer sqrt on 32bit platform. Added stronger typed int_sqrt64 enables the 64bit calculations to be performed on 32bit platforms. Although int_sqrt() is a rough approximation, the same algorithm is used in int_sqrt64() as good enough on 32bit platform.

[]

include/linux/kernel.h

Quoted 1 line
include/linux/kernel.h +0 -0

[]

lib/int_sqrt.c

Quoted 9 lines
include/linux/kernel.h +1 -0
@@ -459,6 +459,7 @@ extern int kernel_text_address(unsigned long addr);
 extern int func_ptr_is_kernel_text(void *ptr);
 
 unsigned long int_sqrt(unsigned long);
+u64 int_sqrt64(u64 x);
 
 extern void bust_spinlocks(int yes);
 extern int oops_in_progress;         /* If set, an oops, panic(), BUG() or die() is in progress */
lib/int_sqrt.c +0 -0

[]

Quoted 20 lines
lib/int_sqrt.c +16 -0
@@ -36,3 +36,29 @@ unsigned long int_sqrt(unsigned long x)
      return y;
 }
 EXPORT_SYMBOL(int_sqrt);
+
+/**
+ * int_sqrt64 - strongly typed int_sqrt function
+ * @x: 64bit integer of which to calculate the sqrt
+ */
+u64 int_sqrt64(u64 x)
+{
+     u64 b, m, y = 0;
+
+     if (x <= 1)
+             return x;
+
+     m = 1ULL << (64 - 2);
+     while (m != 0) {
+             b = y + m;
+             y >>= 1;

lib/int_sqrt.c unsigned long int_sqrt(unsigned long x) · line 64

Quoted 10 lines
lib/int_sqrt.c +10 -0
+
+             if (x >= b) {
+                     x -= b;
+                     y += m;
+             }
+             m >>= 2;
+     }
+     return y;
+}
+EXPORT_SYMBOL(int_sqrt64);

int_sqrt is now optimized with __fls

Because u64 is unsigned long on 64 bit arches, this could probably be optimized for 64 bit distributions with something like:

#if BITS_PER_LONG != 64
#define int_sqrt64 _int_sqrt64
u64 _int_sqrt64(u64 x);
#else
#define int_sqrt64(x) int_sqrt
#endif

Quoted 7 lines

...

#if BITS_PER_LONG != 64
u64 _int_sqrt64(u64 x)
{ etc.. }
#endif

Thanks for the tip. I will respin with this change so that 64 bit arches use the optimized int_sqrt from above.

#3 lore raw
In reply to Crt Mori
Quoted 5 lines · Crt Mori

There is no option to perform 64bit integer sqrt on 32bit platform. Added stronger typed int_sqrt64 enables the 64bit calculations to be performed on 32bit platforms. Although int_sqrt() is a rough approximation, the same algorithm is used in int_sqrt64() as good enough on 32bit platform.

You clearly haven't read a recent version of the file you're patching. Please take a moment to do so now.

lib/int_sqrt.c unsigned long int_sqrt(unsigned long x) · line 44

Quoted 5 lines
lib/int_sqrt.c +5 -0
+/**
+ * int_sqrt64 - strongly typed int_sqrt function
+ * @x: 64bit integer of which to calculate the sqrt
+ */
+u64 int_sqrt64(u64 x)

Please explain how the result of sqrt(u64) can be larger than u32.

Also, I expect that this fact could be exploited to optimize this for 32bit archs if one were so inclined.

Quoted 9 lines
lib/int_sqrt.c +9 -0
+{
+	u64 b, m, y = 0;
+
+	if (x <= 1)
+		return x;
+
+	m = 1ULL << (64 - 2);
+	while (m != 0) {
+		b = y + m;

lib/int_sqrt.c unsigned long int_sqrt(unsigned long x) · line 63

Quoted 10 lines
lib/int_sqrt.c +10 -0
+		y >>= 1;
+
+		if (x >= b) {
+			x -= b;
+			y += m;
+		}
+		m >>= 2;
+	}
+	return y;
+}

so yeah, no, please try again after reading the current file.

author
#4 lore raw
Quoted 10 lines · Peter Zijlstra
Quoted 5 lines · Crt Mori

There is no option to perform 64bit integer sqrt on 32bit platform. Added stronger typed int_sqrt64 enables the 64bit calculations to be performed on 32bit platforms. Although int_sqrt() is a rough approximation, the same algorithm is used in int_sqrt64() as good enough on 32bit platform.

You clearly haven't read a recent version of the file you're patching. Please take a moment to do so now.

IIO kernel does not have the recent version in, so thanks for heads up. It does not change much for my function.

Quoted 8 lines

lib/int_sqrt.c unsigned long int_sqrt(unsigned long x) · line 44

Quoted 5 lines
lib/int_sqrt.c +5 -0
+/**
+ * int_sqrt64 - strongly typed int_sqrt function
+ * @x: 64bit integer of which to calculate the sqrt
+ */
+u64 int_sqrt64(u64 x)

Please explain how the result of sqrt(u64) can be larger than u32.

My hand calculator tells me it could be.

ffffffff=C3=97ffffffff =3D FFFFFFFE00000001 which still has some margin whi= ch
will end up above the 32 bit number. Further more the __fls optimization automatically casts the inputs to unsigned long (32 bit on 32 bit machines), so that also makes it out of option.

Quoted 24 lines

Also, I expect that this fact could be exploited to optimize this for 32bit archs if one were so inclined.

Quoted 9 lines
(quoted diff) +9 -0
+{
+     u64 b, m, y =3D 0;
+
+     if (x <=3D 1)
+             return x;
+
+     m =3D 1ULL << (64 - 2);
+     while (m !=3D 0) {
+             b =3D y + m;

Review

Quoted 10 lines
(quoted diff) +10 -0
+             y >>=3D 1;
+
+             if (x >=3D b) {
+                     x -=3D b;
+                     y +=3D m;
+             }
+             m >>=3D 2;
+     }
+     return y;
+}

so yeah, no, please try again after reading the current file.

#5 lore raw
Quoted 1 line · Crt Mori

IIO kernel does not have the recent version in, so thanks for heads

IIO?

Quoted 1 line

up. It does not change much for my function.

The comment says:

* Computes: floor(sqrt(x))

floor(sqrt(2^64-1)) == 2^32-1

author
#6 lore raw
Quoted 5 lines · Peter Zijlstra
Quoted 1 line · Crt Mori

IIO kernel does not have the recent version in, so thanks for heads

IIO?

Industrial Input / Output Subsytem tree

Quoted 8 lines
Quoted 1 line

up. It does not change much for my function.

The comment says:

* Computes: floor(sqrt(x))

floor(sqrt(2^64-1)) == 2^32-1

OK, so return value should be u32.