From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-0.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4F5D2C433E1 for ; Fri, 12 Jun 2020 12:02:36 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id ED476207D8 for ; Fri, 12 Jun 2020 12:02:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org ED476207D8 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=arndb.de Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 52C048D00BF; Fri, 12 Jun 2020 08:02:35 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 4DBA08D00A0; Fri, 12 Jun 2020 08:02:35 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3CB2D8D00BF; Fri, 12 Jun 2020 08:02:35 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0231.hostedemail.com [216.40.44.231]) by kanga.kvack.org (Postfix) with ESMTP id 237A48D00A0 for ; Fri, 12 Jun 2020 08:02:35 -0400 (EDT) Received: from smtpin13.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay05.hostedemail.com (Postfix) with ESMTP id D44A8181ABE8E for ; Fri, 12 Jun 2020 12:02:34 +0000 (UTC) X-FDA: 76920422628.13.sky81_2d172c326ddc Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin13.hostedemail.com (Postfix) with ESMTP id A385318140B60 for ; Fri, 12 Jun 2020 12:02:34 +0000 (UTC) X-HE-Tag: sky81_2d172c326ddc X-Filterd-Recvd-Size: 7220 Received: from mout.kundenserver.de (mout.kundenserver.de [212.227.126.133]) by imf45.hostedemail.com (Postfix) with ESMTP for ; Fri, 12 Jun 2020 12:02:33 +0000 (UTC) Received: from mail-qv1-f42.google.com ([209.85.219.42]) by mrelayeu.kundenserver.de (mreue011 [212.227.15.129]) with ESMTPSA (Nemesis) id 1MhDN4-1jEWEX46RG-00eOEH for ; Fri, 12 Jun 2020 14:02:32 +0200 Received: by mail-qv1-f42.google.com with SMTP id dp10so4194477qvb.10 for ; Fri, 12 Jun 2020 05:02:31 -0700 (PDT) X-Gm-Message-State: AOAM532vvymuRENEWNpnBsq5XyApsuyF30xq1NmkVkDuWu5h4/O4jXwP 2LuKmOJxdxp+g9ObyoqTpUY3TMuxCAMyYfYjHLs= X-Google-Smtp-Source: ABdhPJwaC0q8qhyefJKAApvPQhwFQE9nP2a9nN27A+JIasUQypms2Mw76+TpVRTnJXgj3VyngfdGI9MrYEpUMtvmB5I= X-Received: by 2002:a0c:ba0c:: with SMTP id w12mr12628573qvf.4.1591963350524; Fri, 12 Jun 2020 05:02:30 -0700 (PDT) MIME-Version: 1.0 References: <9e1de19f35e2d5e1d115c9ec3b7c3284b4a4e077.1591885760.git.afzal.mohd.ma@gmail.com> In-Reply-To: <9e1de19f35e2d5e1d115c9ec3b7c3284b4a4e077.1591885760.git.afzal.mohd.ma@gmail.com> From: Arnd Bergmann Date: Fri, 12 Jun 2020 14:02:13 +0200 X-Gmail-Original-Message-ID: Message-ID: Subject: Re: [RFC 1/3] lib: copy_{from,to}_user using gup & kmap_atomic() To: afzal mohammed Cc: Russell King - ARM Linux admin , Linus Walleij , "linux-kernel@vger.kernel.org" , Linux-MM , Linux ARM , Nicolas Pitre , Catalin Marinas , Will Deacon Content-Type: text/plain; charset="UTF-8" X-Provags-ID: V03:K1:McTeSr0HlPjDZ+CM+fd6H1RhfPrOB335F+6VZY6QuNbF5764sfg fjZs1nS/kaOHpYi/cUZH0rntkVhdxukHUPp7nAVoouB7/0cxlJRai3hbYQEXOYxi3AtQ7yI e1Bep3uM/NtyYEDY3tOFtpVK8+7iip8Yrj+/TZX7j68SRbdeGeoy+uEf0QLxu4OamDxno75 MeuChNIAhKHJpPFqM2SzA== X-UI-Out-Filterresults: notjunk:1;V03:K0:oZj6pMYJnXo=:WgMpaEaX9bYHUbLY7opooZ gvfQ152fzgKBcP/7jZnlfjw67/36k0j/sJbAKyMvJZsK1CQadhGon+D4Vb/rzKBVAK3+dTri+ +UKTNHVDsgGEgCAEualBimkZt3U5Bj4Qp+L8whco0SSUDhcHybx7kHJyxlYnNSPD/wlOWUgwJ zQ5DhN/vcm9kuhW4LdmhCmOMYkkTxx3uySiw4rE/nGEqA/w29HzEjUD+RqkO0IOgb0Lmybwc1 D+Skn3KJ1znmHlYqweqqB8xwRjn4sBYVcsYTsM8PFEQragX0G+KAAPZcvMh/oxtVHsb6ZIwga FrgTc02KJtL2PomzS7ucEGlXfA9VqBr4zg1Q6E19e4EUDvma/9xJvLARjcrb2Bk4b9L44bq31 h42a7mhBvlKBzFtJSOe610WKrkxsrZN56ssTrG6gr502sou1zzLKS/KkGrhnkoIZACj3oB8q7 EE3TMNY9oAnNaiVX+7k2ZdCnj63K3h1WO4Rabb6nru6OkrdojiCtuhzUVBjPltHrPK7y1zSIQ clYRt9wBlfsVqeaAFp/TgvsMB+ymTK5lR5GALTGI829XhQ0xI5fm8FvhpaK9kUz0h9mVhRYLO 9i806zJsqdODQyflKoxWoVxe8zzHb4yaZBdv4araEhG95uAmm2Mhplsc1CO5lNv3W7SrGMG57 5+vatE4a4+fZa9uDL5roRwogKWuohMEZXA1N34GbZgxhOicWOesWpS4AAAiiCgJ0RLFWMbvTo IFmD/hCcHlQ3SRknwYmWTQSUm6eTZW7NJOT26dEkEdOJm2vXOUWIJ1xEBLrIcd3yktrvfs499 5MOngFK2blRbgUYrMVEIo1x0Pb/Aca4HdfFHTxrTdAxaTysr4A= X-Rspamd-Queue-Id: A385318140B60 X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam05 X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: On Fri, Jun 12, 2020 at 12:18 PM afzal mohammed wrote: > > copy_{from,to}_user() uaccess helpers are implemented by user page > pinning, followed by temporary kernel mapping & then memcpy(). This > helps to achieve user page copy when current virtual address mapping > of the CPU excludes user pages. > > Performance wise, results are not encouraging, 'dd' on tmpfs results, > > ARM Cortex-A8, BeagleBone White (256MiB RAM): > w/o series - ~29.5 MB/s > w/ series - ~20.5 MB/s > w/ series & highmem disabled - ~21.2 MB/s > > On Cortex-A15(2GiB RAM) in QEMU: > w/o series - ~4 MB/s > w/ series - ~2.6 MB/s > > Roughly a one-third drop in performance. Disabling highmem improves > performance only slightly. > > 'hackbench' also showed a similar pattern. > > uaccess routines using page pinning & temporary kernel mapping is not > something new, it has been done long long ago by Ingo [1] as part of > 4G/4G user/kernel mapping implementation on x86, though not merged in > mainline. > > [1] https://lore.kernel.org/lkml/Pine.LNX.4.44.0307082332450.17252-100000@localhost.localdomain/ Nice changelog text! I agree the performance drop is not great. There are probably some things that can be done to optimize it, but I guess most of the overhead is from the page table operations and cannot be avoided. What was the exact 'dd' command you used, in particular the block size? Note that by default, 'dd' will request 512 bytes at a time, so you usually only access a single page. It would be interesting to see the overhead with other typical or extreme block sizes, e.g. '1', '64', '4K', '64K' or '1M'. If you want to drill down into where exactly the overhead is (i.e. get_user_pages or kmap_atomic, or something different), using 'perf record dd ..', and 'perf report' may be helpful. > +static int copy_chunk_from_user(unsigned long from, int len, void *arg) > +{ > + unsigned long *to_ptr = arg, to = *to_ptr; > + > + memcpy((void *) to, (void *) from, len); > + *to_ptr += len; > + return 0; > +} > + > +static int copy_chunk_to_user(unsigned long to, int len, void *arg) > +{ > + unsigned long *from_ptr = arg, from = *from_ptr; > + > + memcpy((void *) to, (void *) from, len); > + *from_ptr += len; > + return 0; > +} Will gcc optimize away the indirect function call and inline everything? If not, that would be a small part of the overhead. > +unsigned long gup_kmap_copy_from_user(void *to, const void __user *from, unsigned long n) > +{ > + struct page **pages; > + int num_pages, ret, i; > + > + if (uaccess_kernel()) { > + memcpy(to, (__force void *)from, n); > + return 0; > + } > + > + num_pages = DIV_ROUND_UP((unsigned long)from + n, PAGE_SIZE) - > + (unsigned long)from / PAGE_SIZE; Make sure this doesn't turn into actual division operations but uses shifts. It might even be clearer here to open-code the shift operation so readers can see what this is meant to compile into. > + pages = kmalloc_array(num_pages, sizeof(*pages), GFP_KERNEL | __GFP_ZERO); > + if (!pages) > + goto end; Another micro-optimization may be to avoid the kmalloc for the common case, e.g. anything with "num_pages <= 64", using an array on the stack. > + ret = get_user_pages_fast((unsigned long)from, num_pages, 0, pages); > + if (ret < 0) > + goto free_pages; > + > + if (ret != num_pages) { > + num_pages = ret; > + goto put_pages; > + } I think this is technically incorrect: if get_user_pages_fast() only gets some of the pages, you should continue with the short buffer and return the number of remaining bytes rather than not copying anything. I think you did that correctly for a failed kmap_atomic(), but this has to use the same logic. Arnd