[Devel] [PATCH vz8] x86_64, vclock_gettime: Use standart division instead of __iter_div_u64_rem()

Andrey Ryabinin aryabinin at virtuozzo.com
Tue Nov 3 18:02:47 MSK 2020


timespec_sub_ns() historically uses __iter_div_u64_rem() for division.
Probably it's supposed to be faster

	/*
	 * Iterative div/mod for use when dividend is not expected to be much
	 * bigger than divisor.
	 */
	u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)

However in our case ve_start_time may make dividend much bigger than divisor.
So let's use standard "/" instead of iterative one. With 0 ve_start_time
I wasn't able to see measurable difference, however with big ve_start_time
the difference is rather significant:

 # time ./clock_iter_div
real    1m30.224s
user    1m30.343s
sys     0m0.008s

 # time taskset ./clock_div
real    0m2.757s
user    0m1.730s
sys     0m0.066s

32-bit vdso doesn't like 64-bit division and doesn't link.
I think it needs __udivsi3(). So just fallback to __iter_div_u64_rem()
on 32-bit.

https://jira.sw.ru/browse/PSBM-121856
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
---
 arch/x86/entry/vdso/vclock_gettime.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c
index be1de6c4cafa..224dbe80da66 100644
--- a/arch/x86/entry/vdso/vclock_gettime.c
+++ b/arch/x86/entry/vdso/vclock_gettime.c
@@ -229,13 +229,27 @@ notrace static int __always_inline do_realtime(struct timespec *ts)
 	return mode;
 }
 
+static inline u64 divu64(u64 dividend, u32 divisor, u64 *remainder)
+{
+	/* 32-bit wants __udivsi3() and fails to link, so fallback to iter */
+#ifndef BUILD_VDSO32
+	u64 res;
+
+	res = dividend/divisor;
+	*remainder = dividend % divisor;
+	return res;
+#else
+	return __iter_div_u64_rem(dividend, divisor, remainder);
+#endif
+}
+
 static inline void timespec_sub_ns(struct timespec *ts, u64 ns)
 {
 	if ((s64)ns <= 0) {
-		ts->tv_sec += __iter_div_u64_rem(-ns, NSEC_PER_SEC, &ns);
+		ts->tv_sec += divu64(-ns, NSEC_PER_SEC, &ns);
 		ts->tv_nsec = ns;
 	} else {
-		ts->tv_sec -= __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
+		ts->tv_sec -= divu64(ns, NSEC_PER_SEC, &ns);
 		if (ns) {
 			ts->tv_sec--;
 			ns = NSEC_PER_SEC - ns;
-- 
2.26.2



More information about the Devel mailing list