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=-15.1 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_FORGED_FROMDOMAIN,FREEMAIL_FROM, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_PATCH,MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING,SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS autolearn=unavailable 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 2BCCCC433E1 for ; Thu, 13 Aug 2020 02:18:04 +0000 (UTC) Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by mail.kernel.org (Postfix) with ESMTP id CB0AC20774 for ; Thu, 13 Aug 2020 02:18:03 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="B02TjkNf" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org CB0AC20774 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=owner-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix) id 4F2888D0001; Wed, 12 Aug 2020 22:18:03 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 47BC46B0007; Wed, 12 Aug 2020 22:18:03 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 2F6CF8D0001; Wed, 12 Aug 2020 22:18:03 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from forelay.hostedemail.com (smtprelay0005.hostedemail.com [216.40.44.5]) by kanga.kvack.org (Postfix) with ESMTP id 0EEE86B0006 for ; Wed, 12 Aug 2020 22:18:03 -0400 (EDT) Received: from smtpin22.hostedemail.com (10.5.19.251.rfc1918.com [10.5.19.251]) by forelay01.hostedemail.com (Postfix) with ESMTP id C8A0E180AD804 for ; Thu, 13 Aug 2020 02:18:02 +0000 (UTC) X-FDA: 77143935204.22.voice23_2603b0a26ff0 Received: from filter.hostedemail.com (10.5.16.251.rfc1918.com [10.5.16.251]) by smtpin22.hostedemail.com (Postfix) with ESMTP id 9918718038E67 for ; Thu, 13 Aug 2020 02:18:02 +0000 (UTC) X-HE-Tag: voice23_2603b0a26ff0 X-Filterd-Recvd-Size: 22270 Received: from mail-il1-f195.google.com (mail-il1-f195.google.com [209.85.166.195]) by imf33.hostedemail.com (Postfix) with ESMTP for ; Thu, 13 Aug 2020 02:18:01 +0000 (UTC) Received: by mail-il1-f195.google.com with SMTP id q14so4242806ilj.8 for ; Wed, 12 Aug 2020 19:18:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc:content-transfer-encoding; bh=QwZHs0mA1ZTf1L7B2h/bEEm86SboffLIeiF7JxWmh8k=; b=B02TjkNf9M++pS8b2DcjI2h12OLUfHl6Tj1++eYU6itGtAoDRwREisN1SGorScMlu9 gihDSoEcm3jPTlwHrhivCHs9BgVvgt9gTYTDU/HqbbZnFg4tXJvl3vA0SyoUP/iuFxhB CDbURHzwKVofflOElqNtltDrc4KxogJFC99ctsXTx/YsKD0y0J2UlVXeot89T8uMeJPR B3aVRCDNFJpQxSUp+Q6Xt2Z8cDE+Yz7r/ydYdD+Bhh+vvjHSLyEEOwL04nQ36G3jL8b7 a77ZjPdhB14NcWGyDgsuN4EcfJyzE68AZrw7N8sA3ja3IVvUmYSeWOZpxgb1Qbqa2rq4 jekQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc:content-transfer-encoding; bh=QwZHs0mA1ZTf1L7B2h/bEEm86SboffLIeiF7JxWmh8k=; b=SJXX7VU0qEONHxmbmkvvIccLaEJ2XcT9AptyDkHtMMZpuQ1XzcJ8E11R66j3VK5Exd nFWkrx+vUIU40jRbxslrkrEJ/ZXPoUIycLhfXEzefsQpIi4mQAYaFuZgkg4piPe3cEmK nVxpxRl+QtYgtnDwGPZcm+hNXDjLhN08x80eA7uUpP4bwNCwPz4HZdxj5i3fT7ZSCS2n HhxT4mSvdJo+7CxWeqY/tZyEJmvMIhzjAL10xxiUMxxSknaSESu7nxzFfkTQBKztCC1n g0OhHXbFqyBVXoo69aO5p4FW6QooosEUfGrynTsZQ8sOZb3tSRX2mHI3PGiRkjopCkA8 AZqg== X-Gm-Message-State: AOAM531jWjB38yHTR1vp4YHJ/sTmhJ4tkRx3SAGsmEwqutieoe1aq2rz f5MDMJQ8mz5hHINS4WC/a+SOxgH0GQybI1NORh0= X-Google-Smtp-Source: ABdhPJziFYMfpg6qkwS57T56FpwaUek5Zj+UnZTA3lN9vtb4Ym7UkxYM/5Aq0LWz6WGHMvwCz/2R0OWVwhO3KGSKwzw= X-Received: by 2002:a92:d646:: with SMTP id x6mr2574836ilp.237.1597285080761; Wed, 12 Aug 2020 19:18:00 -0700 (PDT) MIME-Version: 1.0 References: <1595681998-19193-1-git-send-email-alex.shi@linux.alibaba.com> <1595681998-19193-15-git-send-email-alex.shi@linux.alibaba.com> <241ca157-104f-4f0d-7d5b-de394443788d@linux.alibaba.com> <8dbd004e-8eba-f1ec-a5eb-5dc551978936@linux.alibaba.com> <9581db48-cef3-788a-7f5a-8548fee56c13@linux.alibaba.com> <3828d045-17e4-16aa-f0e6-d5dda7ad6b1b@linux.alibaba.com> In-Reply-To: <3828d045-17e4-16aa-f0e6-d5dda7ad6b1b@linux.alibaba.com> From: Alexander Duyck Date: Wed, 12 Aug 2020 19:17:49 -0700 Message-ID: Subject: Re: [PATCH v17 14/21] mm/compaction: do page isolation first in compaction To: Alex Shi Cc: Andrew Morton , Mel Gorman , Tejun Heo , Hugh Dickins , Konstantin Khlebnikov , Daniel Jordan , Yang Shi , Matthew Wilcox , Johannes Weiner , kbuild test robot , linux-mm , LKML , cgroups@vger.kernel.org, Shakeel Butt , Joonsoo Kim , Wei Yang , "Kirill A. Shutemov" , Rong Chen Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Rspamd-Queue-Id: 9918718038E67 X-Spamd-Result: default: False [0.00 / 100.00] X-Rspamd-Server: rspam04 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 Wed, Aug 12, 2020 at 6:47 PM Alex Shi wrote= : > > > > =E5=9C=A8 2020/8/13 =E4=B8=8A=E5=8D=8812:51, Alexander Duyck =E5=86=99=E9= =81=93: > > On Wed, Aug 12, 2020 at 4:44 AM Alex Shi w= rote: > >> > >> > >> > >> =E5=9C=A8 2020/8/11 =E4=B8=8B=E5=8D=8810:47, Alexander Duyck =E5=86=99= =E9=81=93: > >>> On Tue, Aug 11, 2020 at 1:23 AM Alex Shi = wrote: > >>>> > >>>> > >>>> > >>>> =E5=9C=A8 2020/8/10 =E4=B8=8B=E5=8D=8810:41, Alexander Duyck =E5=86= =99=E9=81=93: > >>>>> On Mon, Aug 10, 2020 at 6:10 AM Alex Shi wrote: > >>>>>> > >>>>>> > >>>>>> > >>>>>> =E5=9C=A8 2020/8/7 =E4=B8=8B=E5=8D=8810:51, Alexander Duyck =E5=86= =99=E9=81=93: > >>>>>>> I wonder if this entire section shouldn't be restructured. This i= s the > >>>>>>> only spot I can see where we are resetting the LRU flag instead o= f > >>>>>>> pulling the page from the LRU list with the lock held. Looking ov= er > >>>>>>> the code it seems like something like that should be possible. I = am > >>>>>>> not sure the LRU lock is really protecting us in either the > >>>>>>> PageCompound check nor the skip bits. It seems like holding a > >>>>>>> reference on the page should prevent it from switching between > >>>>>>> compound or not, and the skip bits are per pageblock with the LRU= bits > >>>>>>> being per node/memcg which I would think implies that we could ha= ve > >>>>>>> multiple LRU locks that could apply to a single skip bit. > >>>>>> > >>>>>> Hi Alexander, > >>>>>> > >>>>>> I don't find problem yet on compound or skip bit usage. Would you = clarify the > >>>>>> issue do you concerned? > >>>>>> > >>>>>> Thanks! > >>>>> > >>>>> The point I was getting at is that the LRU lock is being used to > >>>>> protect these and with your changes I don't think that makes sense > >>>>> anymore. > >>>>> > >>>>> The skip bits are per-pageblock bits. With your change the LRU lock= is > >>>>> now per memcg first and then per node. As such I do not believe it > >>>>> really provides any sort of exclusive access to the skip bits. I st= ill > >>>>> have to look into this more, but it seems like you need a lock per > >>>>> either section or zone that can be used to protect those bits and d= eal > >>>>> with this sooner rather than waiting until you have found an LRU pa= ge. > >>>>> The one part that is confusing though is that the definition of the > >>>>> skip bits seems to call out that they are a hint since they are not > >>>>> protected by a lock, but that is exactly what has been happening he= re. > >>>>> > >>>> > >>>> The skip bits are safe here, since even it race with other skip acti= on, > >>>> It will still skip out. The skip action is try not to compaction too= much, > >>>> not a exclusive action needs avoid race. > >>> > >>> That would be the case if it didn't have the impact that they > >>> currently do on the compaction process. What I am getting at is that = a > >>> race was introduced when you placed this test between the clearing of > >>> the LRU flag and the actual pulling of the page from the LRU list. So > >>> if you tested the skip bits before clearing the LRU flag then I would > >>> be okay with the code, however because it is triggering an abort afte= r > >> > >> Hi Alexander, > >> > >> Thanks a lot for comments and suggestions! > >> > >> I have tried your suggestion: > >> > >> Signed-off-by: Alex Shi > >> --- > >> mm/compaction.c | 14 +++++++------- > >> 1 file changed, 7 insertions(+), 7 deletions(-) > >> > >> diff --git a/mm/compaction.c b/mm/compaction.c > >> index b99c96c4862d..6c881dee8c9a 100644 > >> --- a/mm/compaction.c > >> +++ b/mm/compaction.c > >> @@ -988,6 +988,13 @@ static bool too_many_isolated(pg_data_t *pgdat) > >> if (__isolate_lru_page_prepare(page, isolate_mode) != =3D 0) > >> goto isolate_fail_put; > >> > >> + /* Try get exclusive access under lock */ > >> + if (!skip_updated) { > >> + skip_updated =3D true; > >> + if (test_and_set_skip(cc, page, low_pfn)) > >> + goto isolate_fail_put; > >> + } > >> + > >> /* Try isolate the page */ > >> if (!TestClearPageLRU(page)) > >> goto isolate_fail_put; > > > > I would have made this much sooner. Probably before you call > > get_page_unless_zero so as to avoid the unnecessary atomic operations. > > > >> @@ -1006,13 +1013,6 @@ static bool too_many_isolated(pg_data_t *pgdat) > >> > >> lruvec_memcg_debug(lruvec, page); > >> > >> - /* Try get exclusive access under lock */ > >> - if (!skip_updated) { > >> - skip_updated =3D true; > >> - if (test_and_set_skip(cc, page, low_pf= n)) > >> - goto isolate_abort; > >> - } > >> - > >> /* > >> * Page become compound since the non-locked c= heck, > >> * and it's on LRU. It can only be a THP so th= e order > >> -- > >> > >> Performance of case-lru-file-mmap-read in vm-scalibity is dropped a bi= t. not > >> helpful > > > > So one issue with this change is that it is still too late to be of > > much benefit. Really you should probably be doing this much sooner, > > for example somewhere before the get_page_unless_zero(). Also the > > thing that still has me scratching my head is the "Try get exclusive > > access under lock" comment. The function declaration says this is > > supposed to be a hint, but we were using the LRU lock to synchronize > > it. I'm wondering if we should really be protecting this with the zone > > lock since we are modifying the pageblock flags which also contain the > > migration type value for the pageblock and are only modified while > > holding the zone lock. > > zone lock is probability better. you can try and test. So I spent a good chunk of today looking the code over and what I realized is that we probably don't even really need to have this code protected by the zone lock since the LRU bit in the pageblock should do most of the work for us. In addition we can get rid of the test portion of this and just make it a set only operation if I am not mistaken. > >>> the LRU flag is cleared then you are creating a situation where > >>> multiple processes will be stomping all over each other as you can > >>> have each thread essentially take a page via the LRU flag, but only > >>> one thread will process a page and it could skip over all other pages > >>> that preemptively had their LRU flag cleared. > >> > >> It increase a bit crowd here, but lru_lock do reduce some them, and sk= ip_bit > >> could stop each other in a array check(bitmap). So compare to whole no= de > >> lru_lock, the net profit is clear in patch 17. > > > > My concern is that what you can end up with is multiple threads all > > working over the same pageblock for isolation. With the old code the > > LRU lock was used to make certain that test_and_set_skip was being > > synchronized on the first page in the pageblock so you would only have > > one thread going through and working a single pageblock. However after > > your changes it doesn't seem like the test_and_set_skip has that > > protection since only one thread will ever be able to successfully > > call it for the first page in the pageblock assuming that the LRU flag > > is set on the first page in the pageblock block. > > > >>> > >>> If you take a look at the test_and_set_skip the function only acts on > >>> the pageblock aligned PFN for a given range. WIth the changes you hav= e > >>> in place now that would mean that only one thread would ever actually > >>> call this function anyway since the first PFN would take the LRU flag > >>> so no other thread could follow through and test or set the bit as > >> > >> Is this good for only one process could do test_and_set_skip? is that > >> the 'skip' meaning to be? > > > > So only one thread really getting to fully use test_and_set_skip is > > good, however the issue is that there is nothing to synchronize the > > testing from the other threads. As a result the other threads could > > have isolated other pages within the pageblock before the thread that > > is calling test_and_set_skip will get to complete the setting of the > > skip bit. This will result in isolation failures for the thread that > > set the skip bit which may be undesirable behavior. > > > > With the old code the threads were all synchronized on testing the > > first PFN in the pageblock while holding the LRU lock and that is what > > we lost. My concern is the cases where skip_on_failure =3D=3D true are > > going to fail much more often now as the threads can easily interfere > > with each other. > > I have a patch to fix this, which is on > https://github.com/alexshi/linux.git lrunext I don't think that patch helps to address anything. You are now failing to set the bit in the case that something modifies the pageblock flags while you are attempting to do so. I think it would be better to just leave the cmpxchg loop as it is. > > > >>> well. The expectation before was that all threads would encounter thi= s > >>> test and either proceed after setting the bit for the first PFN or > >>> abort after testing the first PFN. With you changes only the first > >>> thread actually runs this test and then it and the others will likely > >>> encounter multiple failures as they are all clearing LRU bits > >>> simultaneously and tripping each other up. That is why the skip bit > >>> must have a test and set done before you even get to the point of > >>> clearing the LRU flag. > >> > >> It make the things warse in my machine, would you like to have a try b= y yourself? > > > > I plan to do that. I have already been working on a few things to > > clean up and optimize your patch set further. I will try to submit an > > RFC this evening so we can discuss. > > > > Glad to see your new code soon. Would you like do it base on > https://github.com/alexshi/linux.git lrunext I can rebase off of that tree. It may add another half hour or so. I have barely had any time to test my code. When I enabled some of the debugging features in the kernel related to using the vm-scalability tests the boot time became incredibly slow so I may just make certain I can boot and not mess the system up before submitting my patches as an RFC. I can probably try testing them more tomorrow. > >>> > >>>>> The point I was getting at with the PageCompound check is that inst= ead > >>>>> of needing the LRU lock you should be able to look at PageCompound = as > >>>>> soon as you call get_page_unless_zero() and preempt the need to set > >>>>> the LRU bit again. Instead of trying to rely on the LRU lock to > >>>>> guarantee that the page hasn't been merged you could just rely on t= he > >>>>> fact that you are holding a reference to it so it isn't going to > >>>>> switch between being compound or order 0 since it cannot be freed. = It > >>>>> spoils the idea I originally had of combining the logic for > >>>>> get_page_unless_zero and TestClearPageLRU into a single function, b= ut > >>>>> the advantage is you aren't clearing the LRU flag unless you are > >>>>> actually going to pull the page from the LRU list. > >>>> > >>>> Sorry, I still can not follow you here. Compound code part is unchan= ged > >>>> and follow the original logical. So would you like to pose a new cod= e to > >>>> see if its works? > >>> > >>> No there are significant changes as you reordered all of the > >>> operations. Prior to your change the LRU bit was checked, but not > >>> cleared before testing for PageCompound. Now you are clearing it > >>> before you are testing if it is a compound page. So if compaction is > >>> running we will be seeing the pages in the LRU stay put, but the > >>> compound bit flickering off and on if the compound page is encountere= d > >>> with the wrong or NULL lruvec. What I was suggesting is that the > >> > >> The lruvec could be wrong or NULL here, that is the base stone of whol= e > >> patchset. > > > > Sorry I had a typo in my comment as well as it is the LRU bit that > > will be flickering, not the compound. The goal here is to avoid > > clearing the LRU bit unless we are sure we are going to take the > > lruvec lock and pull the page from the list. > > > >>> PageCompound test probably doesn't need to be concerned with the lock > >>> after your changes. You could test it after you call > >>> get_page_unless_zero() and before you call > >>> __isolate_lru_page_prepare(). Instead of relying on the LRU lock to > >>> protect us from the page switching between compound and not we would > >>> be relying on the fact that we are holding a reference to the page so > >>> it should not be freed and transition between compound or not. > >>> > >> > >> I have tried the patch as your suggested, it has no clear help on perf= ormance > >> on above vm-scaliblity case. Maybe it's due to we checked the same thi= ng > >> before lock already. > >> > >> diff --git a/mm/compaction.c b/mm/compaction.c > >> index b99c96c4862d..cf2ac5148001 100644 > >> --- a/mm/compaction.c > >> +++ b/mm/compaction.c > >> @@ -985,6 +985,16 @@ static bool too_many_isolated(pg_data_t *pgdat) > >> if (unlikely(!get_page_unless_zero(page))) > >> goto isolate_fail; > >> > >> + /* > >> + * Page become compound since the non-locked c= heck, > >> + * and it's on LRU. It can only be a THP so th= e order > >> + * is safe to read and it's 0 for tail pages. > >> + */ > >> + if (unlikely(PageCompound(page) && !cc->alloc_= contig)) { > >> + low_pfn +=3D compound_nr(page) - 1; > >> + goto isolate_fail_put; > >> + } > >> + > >> if (__isolate_lru_page_prepare(page, isolate_mode) != =3D 0) > >> goto isolate_fail_put; > >> > >> @@ -1013,16 +1023,6 @@ static bool too_many_isolated(pg_data_t *pgdat) > >> goto isolate_abort; > >> } > >> > >> - /* > >> - * Page become compound since the non-locked c= heck, > >> - * and it's on LRU. It can only be a THP so th= e order > >> - * is safe to read and it's 0 for tail pages. > >> - */ > >> - if (unlikely(PageCompound(page) && !cc->alloc_= contig)) { > >> - low_pfn +=3D compound_nr(page) - 1; > >> - SetPageLRU(page); > >> - goto isolate_fail_put; > >> - } > >> } else > >> rcu_read_unlock(); > >> > > > > So actually there is more we could do than just this. Specifically a > > few lines below the rcu_read_lock there is yet another PageCompound > > check that sets low_pfn yet again. So in theory we could combine both > > of those and modify the code so you end up with something more like: > > @@ -968,6 +974,16 @@ isolate_migratepages_block(struct compact_control > > *cc, unsigned long low_pfn, > > if (unlikely(!get_page_unless_zero(page))) > > goto isolate_fail; > > > > + if (PageCompound(page)) { > > + const unsigned int order =3D compound_order(pag= e); > > + > > + if (likely(order < MAX_ORDER)) > > + low_pfn +=3D (1UL << order) - 1; > > + > > + if (unlikely(!cc->alloc_contig)) > > + goto isolate_fail_put; > > > > The current don't check this unless locked changed. But anyway check it > every page may have no performance impact. Yes and no. The same code is also ran outside the lock and that is why I suggested merging the two and creating this block of logic. It will be clearer once I have done some initial smoke testing and submitted my patch. > + } > > + > > if (__isolate_lru_page_prepare(page, isolate_mode) !=3D= 0) > > goto isolate_fail_put; > > > > Doing this you would be more likely to skip over the entire compound > > page in a single jump should you not be able to either take the LRU > > bit or encounter a busy page in __isolate_Lru_page_prepare. I had > > copied this bit from an earlier check and modified it as I was not > > sure I can guarantee that this is a THP since we haven't taken the LRU > > lock yet. However I believe the page cannot be split up while we are > > holding the extra reference so the PageCompound flag and order should > > not change until we call put_page. > > > > It looks like the lock_page protect this instead of get_page that just wo= rks > after split func called. So I thought that the call to page_ref_freeze that is used in functions like split_huge_page_to_list is meant to address this case. What it is essentially doing is setting the reference count to zero if the count is at the expected value. So with the get_page_unless_zero it would either fail because the value is already zero, or the page_ref_freeze would fail because the count would be one higher than the expected value. Either that or I am still missing another piece in the understanding of this. Thanks. - Alex