Received: by 2002:a25:868d:0:0:0:0:0 with SMTP id z13csp3759732ybk; Tue, 19 May 2020 12:16:05 -0700 (PDT) X-Google-Smtp-Source: ABdhPJxOlkbapi0jAdAJPvW9GbmienS21ACjebFc0MIHGphWHw2TX9OQGKrXl2TXM2bwJTbvrU48 X-Received: by 2002:a17:906:68c6:: with SMTP id y6mr640498ejr.437.1589915765201; Tue, 19 May 2020 12:16:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1589915765; cv=none; d=google.com; s=arc-20160816; b=c/lmV4Z/JUopcAwSQ8xSSEiu9Bie1w05+2WKv8yXiOWhbM/f2oV/z/+sh1r/8w6I4e ZIc0EOTMqvqi8HRBo7Cw407lYX5QfGnOg9d4EvIMuYhAzAIx6Qp8llpDsBrbSszI/TtL WUM+cpbgf+g/sO8gdc23bJEf7cu3CUCTLyk1rS+e86DstRn5IfCCakBszVjheXY8fEbd 4Vw4lPfhQVMrIpSJZmFGrAx8/26X6/beXLAbSaWL5rqlQr/AjKQC0svVYu3F7w9OYZ+d KeyccMGUlDsnPNVZtVBuTcWAD7Khq+a6ZMd+3NcJqxEXQRjaFDBR84dApZh1nUY9bf8y igcA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:in-reply-to:content-disposition :mime-version:references:message-id:subject:cc:to:from:date :dkim-signature; bh=GjBFpoyqijPTDxinrjDWXYNyaw2KQR2J7AqFdwF4g6k=; b=dm6r3hQE6vBnRIc93B0TE/pe/DblOTQ8N9niTPFjX35TwzreJepNcQ5+xldR6rdr0R rZ5TGkTZH86dIpcvGePjDNkCXKzWjyLEOWp2fKzMLieqQfcBpOrBuPcWSD5TDT9+pP+N Cfigy/eiMN8eYuDiBoEM6bpNBcfCJpTv4ufV1Roqe/sbPnPeypQUO72qqmdfXRakLI5g 90kxYZU25usdChvze9/IfUTvxn6cx2lJU8qZp5Mym3e/UiBFYGet+ZD8JOP9D6d8Mlcp RlLP1Hu9RAIB/zeLrkvogFIwliDx6KpZj00QMs3XrhDFIvBXZIUwlgG1pz4veC1fsK3I GFQg== ARC-Authentication-Results: i=1; mx.google.com; dkim=fail header.i=@infradead.org header.s=bombadil.20170209 header.b=MtSGQvIv; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id 88si236702edq.491.2020.05.19.12.15.41; Tue, 19 May 2020 12:16:05 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=fail header.i=@infradead.org header.s=bombadil.20170209 header.b=MtSGQvIv; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726722AbgESTME (ORCPT + 99 others); Tue, 19 May 2020 15:12:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44536 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726290AbgESTMD (ORCPT ); Tue, 19 May 2020 15:12:03 -0400 Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DE379C08C5C0 for ; Tue, 19 May 2020 12:12:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20170209; h=In-Reply-To:Content-Type:MIME-Version :References:Message-ID:Subject:Cc:To:From:Date:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=GjBFpoyqijPTDxinrjDWXYNyaw2KQR2J7AqFdwF4g6k=; b=MtSGQvIvgH1Tss3DC3hYhNeTxT q2lE+Al8EsD8UNBIbnrxNJ900THPIoGRJrNE9iEA6ypKcHiBnadMf+Nf2fp8uPgPZ9N1EYhSMa8Pz HycnpOYhuwGijVtD7azMpJrBvMZdSLIFxc9i8h+M3Ed/RlZ1EyEFsg8bw8OQmaPDeDlCdYq81Nm8d gcJeVXJwHRolBcXSkaCz2ZZ460P7qT/KHuwE/1HAJHxYpJjHP9IwbFiL7wqhIMuXKQA1zxScvZN5Y NuGSFUfOxMAyL/TmfTe+c01F9h6Yqml9nu9qCMMGLfDUgaF043z/7lQ8tUSc35ne4hj9cdkJfjpaC 9Ti738XA==; Received: from j217100.upc-j.chello.nl ([24.132.217.100] helo=noisy.programming.kicks-ass.net) by bombadil.infradead.org with esmtpsa (Exim 4.92.3 #3 (Red Hat Linux)) id 1jb7eg-0007Ns-LZ; Tue, 19 May 2020 19:11:58 +0000 Received: from hirez.programming.kicks-ass.net (hirez.programming.kicks-ass.net [192.168.1.225]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by noisy.programming.kicks-ass.net (Postfix) with ESMTPS id 6DF4130067C; Tue, 19 May 2020 21:11:56 +0200 (CEST) Received: by hirez.programming.kicks-ass.net (Postfix, from userid 1000) id 5935825D60CB1; Tue, 19 May 2020 21:11:56 +0200 (CEST) Date: Tue, 19 May 2020 21:11:56 +0200 From: Peter Zijlstra To: Linus Torvalds Cc: Oleg Nesterov , Ingo Molnar , Thomas Gleixner , Andrew Fox , Stephen Johnston , Linux Kernel Mailing List , Stanislaw Gruszka Subject: Re: [PATCH v2] sched/cputime: make scale_stime() more precise Message-ID: <20200519191156.GA325280@hirez.programming.kicks-ass.net> References: <20190718131834.GA22211@redhat.com> <20200127122817.GA10957@redhat.com> <20200519172506.GA317395@hirez.programming.kicks-ass.net> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Tue, May 19, 2020 at 11:33:34AM -0700, Linus Torvalds wrote: > So I'd much rather see it as a weak function defined in > lib/math/div64.c, and then architectures don't even need to override > it at all. Just let them define their own (inline or not) function, > and we have this as a weak fallback. My compiler doesn't like overriding a __weak with a static inline. It complains about redefinitions. It works with extern inline though; but that is fairly rare in the kernel. Still it compiles and generates the right code. --- arch/x86/include/asm/div64.h | 13 +++++++++++-- include/linux/math64.h | 2 ++ kernel/sched/cputime.c | 46 +------------------------------------------- lib/math/div64.c | 39 +++++++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 47 deletions(-) diff --git a/arch/x86/include/asm/div64.h b/arch/x86/include/asm/div64.h index 9b8cb50768c2..320508d797de 100644 --- a/arch/x86/include/asm/div64.h +++ b/arch/x86/include/asm/div64.h @@ -74,16 +74,25 @@ static inline u64 mul_u32_u32(u32 a, u32 b) #else # include -static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 div) +/* + * Will generate an #DE when the result doesn't fit u64, could fix with an + * __ex_table[] entry when it becomes an issue. + */ +extern __always_inline u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div) { u64 q; asm ("mulq %2; divq %3" : "=a" (q) - : "a" (a), "rm" ((u64)mul), "rm" ((u64)div) + : "a" (a), "rm" (mul), "rm" (div) : "rdx"); return q; } + +static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 div) +{ + return mul_u64_u64_div_u64(a, mul, div); +} #define mul_u64_u32_div mul_u64_u32_div #endif /* CONFIG_X86_32 */ diff --git a/include/linux/math64.h b/include/linux/math64.h index 11a267413e8e..d097119419e6 100644 --- a/include/linux/math64.h +++ b/include/linux/math64.h @@ -263,6 +263,8 @@ static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor) } #endif /* mul_u64_u32_div */ +u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div); + #define DIV64_U64_ROUND_UP(ll, d) \ ({ u64 _tmp = (d); div64_u64((ll) + _tmp - 1, _tmp); }) diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index ff9435dee1df..5a55d2300452 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -519,50 +519,6 @@ void account_idle_ticks(unsigned long ticks) account_idle_time(cputime); } -/* - * Perform (stime * rtime) / total, but avoid multiplication overflow by - * losing precision when the numbers are big. - */ -static u64 scale_stime(u64 stime, u64 rtime, u64 total) -{ - u64 scaled; - - for (;;) { - /* Make sure "rtime" is the bigger of stime/rtime */ - if (stime > rtime) - swap(rtime, stime); - - /* Make sure 'total' fits in 32 bits */ - if (total >> 32) - goto drop_precision; - - /* Does rtime (and thus stime) fit in 32 bits? */ - if (!(rtime >> 32)) - break; - - /* Can we just balance rtime/stime rather than dropping bits? */ - if (stime >> 31) - goto drop_precision; - - /* We can grow stime and shrink rtime and try to make them both fit */ - stime <<= 1; - rtime >>= 1; - continue; - -drop_precision: - /* We drop from rtime, it has more bits than stime */ - rtime >>= 1; - total >>= 1; - } - - /* - * Make sure gcc understands that this is a 32x32->64 multiply, - * followed by a 64/32->64 divide. - */ - scaled = div_u64((u64) (u32) stime * (u64) (u32) rtime, (u32)total); - return scaled; -} - /* * Adjust tick based cputime random precision against scheduler runtime * accounting. @@ -622,7 +578,7 @@ void cputime_adjust(struct task_cputime *curr, struct prev_cputime *prev, goto update; } - stime = scale_stime(stime, rtime, stime + utime); + stime = mul_u64_u64_div_u64(stime, rtime, stime + utime); update: /* diff --git a/lib/math/div64.c b/lib/math/div64.c index 368ca7fd0d82..200a151e1be9 100644 --- a/lib/math/div64.c +++ b/lib/math/div64.c @@ -190,3 +190,42 @@ u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder) return __iter_div_u64_rem(dividend, divisor, remainder); } EXPORT_SYMBOL(iter_div_u64_rem); + +__weak u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c) +{ + u64 res = 0, div, rem; + int shift; + + /* can a * b overflow ? */ + if (ilog2(a) + ilog2(b) > 62) { + /* + * (b * a) / c is equal to + * + * (b / c) * a + + * (b % c) * a / c + * + * if nothing overflows. Can the 1st multiplication + * overflow? Yes, but we do not care: this can only + * happen if the end result can't fit in u64 anyway. + * + * So the code below does + * + * res = (b / c) * a; + * b = b % c; + */ + div = div64_u64_rem(b, c, &rem); + res = div * a; + b = rem; + + shift = ilog2(a) + ilog2(b) - 62; + if (shift > 0) { + /* drop precision */ + b >>= shift; + c >>= shift; + if (!c) + return res; + } + } + + return res + div64_u64(a * b, c); +}