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=-5.2 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, USER_AGENT_SANE_1 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 1A671C2D0A3 for ; Thu, 12 Nov 2020 11:17:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7CD4121D40 for ; Thu, 12 Nov 2020 11:17:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727035AbgKLLRy (ORCPT ); Thu, 12 Nov 2020 06:17:54 -0500 Received: from foss.arm.com ([217.140.110.172]:47578 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725902AbgKLLRx (ORCPT ); Thu, 12 Nov 2020 06:17:53 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 9B707139F; Thu, 12 Nov 2020 03:17:52 -0800 (PST) Received: from arm.com (usa-sjc-imap-foss1.foss.arm.com [10.121.207.14]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id EF5883F73C; Thu, 12 Nov 2020 03:17:50 -0800 (PST) Date: Thu, 12 Nov 2020 11:17:47 +0000 From: Dave Martin To: Li Qiang Cc: alexandre.torgue@st.com, catalin.marinas@arm.com, gaoguijin@huawei.com, colordev.jiang@huawei.com, luchunhua@huawei.com, linux-crypto@vger.kernel.org, mcoquelin.stm32@gmail.com, liliang889@huawei.com, will@kernel.org, davem@davemloft.net, linux-arm-kernel@lists.infradead.org, herbert@gondor.apana.org.au Subject: Re: [PATCH 0/1] arm64: Accelerate Adler32 using arm64 SVE instructions. Message-ID: <20201112111745.GS6882@arm.com> References: <20201103121506.1533-1-liqiang64@huawei.com> <20201105165301.GH6882@arm.com> <20201110104629.GJ6882@arm.com> <89a9bdcc-b96e-2f2d-6c52-ca44e0e3472c@huawei.com> <20201110160708.GL6882@arm.com> <484ad2c8-3905-fc98-237c-f7eb4045edbc@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <484ad2c8-3905-fc98-237c-f7eb4045edbc@huawei.com> User-Agent: Mutt/1.5.23 (2014-03-12) Precedence: bulk List-ID: X-Mailing-List: linux-crypto@vger.kernel.org On Thu, Nov 12, 2020 at 03:20:53PM +0800, Li Qiang wrote: > > > 在 2020/11/11 0:07, Dave Martin 写道: > >>>>> add zA.s, pP/m, zA.s, zX.s // zA.s += zX.s > >>>>> > >>>>> msb zX.s, pP/m, zJ.s, zB.s // zX.s := zB.s - zX.s * zJ.s > >>>>> > >>>>> movprfx zB, zA > >>>>> mad zB.s, pP/m, zV.s, zX.s // zB.s := zX.s + zA.s * V > >> I found the bug I encountered earlier, that is, the calculation of zB here > >> needs to use pA with all elements activated. The reason is the same as my > >> previous guess, because all elements of zA should be involved when calculating zB. > >> Because the original calculation formula is like this. > >> > >> For example: > >> In the last loop: > >> left byte is: 3 | 4 | \0 | > >> zA.s is: 100 | 200 | 100 | 200 (sum = 600) > >> pP.s is: 1 | 1 | 0 | 0 (Only activate the first 2 channels) > >> > >> At this time, if the calculation of zB only takes the first 2 active elements, the data > >> is incomplete, because according to the description of the original algorithm, zB is always > >> based on the sum of all the accumulated bytes. > > Yes, you're quite right here: zX is partial: only the elements pP are > > valid; but all elements of zA and zB are always valid. I was focusing > > too much on the handling of the partial input block. > > > >> Here we can simply change the prediction register used in the two sentences related to > >> zB to the one that is all true (it is pA in our code), like this: > >> msb zX.s, pA/m, zJ.s, zB.s // zX.s := zB.s - zX.s * zJ.s > > Are you sure about this? In a final partial block, the trailing > > elements of zX.s beyond pP will be leftover junk from the last > > iteration. > > Yes, I have verified this code and it is correct. The reason is that if pP is used here, > the inactive elements of zB will be ignored in zX, which will cause data loss.(I think it is Yes, you're quite right. I was forgetting about the /z (zeroing) semantics for the ld1b. This means that we get away with not inactivating those elements in the msb instruction, since zeros multiplied by the elements of zJ remain zero. > because the zB data is covered by the multiplication and addition results of zX, zA, and zV > using movprfx and mad. Have I got that right?) :) Yes, I think so. > On the other hand zX uses the prediction register pP/z when loading data, the value of the > inactive element is 0, the inactive element in zX will not affect the final result, the inactive > element in zB will be directly assigned to the inactive element of zX element. > > Then in the next instruction, it will be added to zB along with zX. Yes. This might be part of the reason why the architects decided that SVE loads zero the inactive elements instead of leaving them unchanged. > > > > > This might require a bit more thought in order to get the final block > > handling correct. > > > >> trailloop: // Last cycle entrance > >> cntp x6, p1, p0.s // Get active element count of last cycle > >> cpy zV.s, p1/m, w6 // Set zV to the actual value. > > Note that you can also write "mov" here, but I'm not sure which alias is > > preferred> > >> loop: // Core loop entrance > >> ld1b zX.s, p0/z, [x1] > >> incw x1 > >> > >> add zA.s, p0/m, zA.s, zX.s // The calculation of zA still needs to use p0 > >> msb zX.s, p1/m, zJ.s, zB.s // Change p register here > >> movprfx zB, zA > >> mad zB.s, p1/m, zV.s, zX.s // Change p register here > > As discussed above, are you sure this is correct now? I think we've agreed that it is correct. Thinking about the code flow, I think the initialisation of zV is slightly wrong: for very short data, the first block may be shorter than VL. I think this is easily solved by getting rid of the constant initialisation for zV and removing the branch that skips the CNTP code when entering the loop for the first time. That way, zV gets initialised to the correct thing on entering the loop, irrespective of whether we have a whole vector on the first iteration. Note, to squeeze maximum performance out of this, you still probably want to unroll the loop a few times so that you can schedule useful work in between each load and the computations that depend on it. > >> start: > >> whilelo p0.s, x1, xLimit > >> b.last loop // The condition for the core loop to continue is that b.last is true > >> b.first trailloop // If b.last is false and b.first is true, it means the last cycle > >> > >> uaddv d0, p1, zA.s > >> uaddv d1, p1, zB.s > >> > >> mov x12, v0.2d[0] > >> mov x13, v1.2d[0] > > The "2" here seems not to be required by the syntax, although it's > > harmless. > > Yes I deleted it. > > > > >> add x10, x10, x12 > >> add x11, x11, x13 > >> add x11, x11, x2 > > If x10 and x11 are used as accmulators by the caller, I guess this works. > > X10 and X11 are part A and part B of the initial value of adler32 passed in by the caller. Right, that makes sense. > > > > >> mod65521 10, 14, 12 > >> mod65521 11, 14, 12 Note, can you replace these with udiv? While using mul might be slightly cheaper to achieve this, it makes the code more complex and will have a negligible impact on the overall cost... So, does something like this work: mov x3, #65521 udiv x4, x10, x3 udiv x5, x11, x3 msub x10, x4, x3, x10 msub x11, x5, x3, x11 > >> lsl x11, x11, #16 > >> orr x0, x10, x11 > >> ret > >> -->8-- > >> > >> After this modification, The test results are correct when the data length is less than about 8 Kbyte, > >> part A will still be correct after 8K, and an overflow error will occur in part B. This is because A > >> only accumulates all the bytes, and the accumulative acceleration of B expands faster, because the > >> accumulative formula of B is: > >> B = (1 + D1) + (1 + D1 + D2) + ... + (1 + D1 + D2 + ... + Dn) (mod 65521) > >> = n×D1 + (n−1)×D2 + (n−2)×D3 + ... + Dn + n (mod 65521) > >> > >> If we take the average value of Dx to 128 and n to 8192: > >> B = (1 + 2 + ... + 8129) * 128 + 8192 > >> = 4,295,499,776 (32bit overflow) > >> > >> So I think the 32-bit accumulator is still not enough for part B here. :) > >> > >> -- > >> Best regards, > >> Li Qiang > > That makes sense. I hadn't tried to calculate the actual bound. > > > > It may be worth trying this with 64-bit accumulators. This will > > probably slow things down, but it depends on the relative computation / > > memory throughput exhibited by the hardware. > > If a 64-bit wide vector register is used, for most scenes where the amount of data is not particularly large, > is it wasted more vector resources? Yes :) Depending on the algorithm, this might be a better tradeoff if it meant that the data could be processed in larger chunks. I suspect that the tradeoff is unfavourable in this particluar case though -- but I haven't tried it. > Maybe we can also try to use 16-bit wide vector registers to load data and calculations, > and accumulate them into the scalar register xn before overflow, just like my original patch, > but I can try to use ascending order to change the processing of the last loop Be more elegant. Perhaps. But I assumed that 16-bit elements would overflow much too fast to be practical. Just multiplying zX by zJ once can produce element values up to 0xfe01 if VL is 256 bytes. Did you have some idea for how to make this work? It may be possible to do 16-bit multiplies with 32-bit accumulation. SVE2 has some NEON-style mixed-width multiply-accumulate instructions that can achieve this sort of thing directly, but in SVE(1) I think you would have to break the multiply-accumulates up. Say: mul zX.h, pP/m, zX.h, zJ.h sub zX.s, pP/m, zB.s, zX.s whilelo pP.s should generate a predicate with odd .h elements inactive, and ld1b zX.s, pP/z, ... will make sure those elements are all zeroed in xX.h. I'm not sure this would be faster than a single 32-bit msb, since multiply-accumulates are likely to be heavily optimised in the hardware, but you could try it. > > > > I think the code can't be bulletproof without breaking the input into > > chunks anyway, though. > > I don't quite understand what it means here. Does it mean that the input bytes are read into the vector in > blocks for calculation (this is how it is done now) or the intermediate results are stored in different elements > of the vector in blocks during the calculation process? :-) I mean, you limit the number of iterations of the core loop so that overflow doesn't happen. You're already doing this; I just wanted to make the point that 64-bit accumulators probably don't solve this problem, even though it will take a very large number of iterations to cause an overflow. Unless Adler32 specifies the maximum length of the input data not to exceed some value, it could go on forever -- so overflow becomes inevitable. Cheers ---Dave 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=-5.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_SANE_1 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 954CFC2D0A3 for ; Thu, 12 Nov 2020 11:19:20 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0F81F21D40 for ; Thu, 12 Nov 2020 11:19:20 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="p6Th5+Lz" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 0F81F21D40 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=arm.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:In-Reply-To:MIME-Version:References:Message-ID: Subject:To:From:Date:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=eF8oyKBXzF6plIC1lnEMenLaz26H9E9FidQ/ZH+w8ss=; b=p6Th5+LzEo7VdMI0Y/yGknAcd Z+j08iSwByMWHSVB39nWJ+N87oQ8KKM9surlxNdJSFCRZGAw4qTQtKaiU/h2m8MPmgHJinjCD92Ww /NYjLSaG9Z/vC0XsxvU9kurB4z2erkyhpNLHDE4bM8mWJcsoHzkAEQI3Dtdm2h5RjZ7Kcn69anFxd F3UIpFwzhGafFS6Dd8rVxAsY+7JwpQbLbRCX21cL6v0dXXuEGLsEIkl/ulAvQvAQWc/sWHtmAQmDz NQ4YY7+WMYkJR6QWlRclB1rCN6Lg8Bz7cV28N+RzsLLIvl6V+odSgo154YBRlXvMZxTOUFou5bhA3 sQJt0k2kg==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kdAc4-00030N-Cy; Thu, 12 Nov 2020 11:18:00 +0000 Received: from foss.arm.com ([217.140.110.172]) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kdAbx-0002zW-At for linux-arm-kernel@lists.infradead.org; Thu, 12 Nov 2020 11:17:56 +0000 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 9B707139F; Thu, 12 Nov 2020 03:17:52 -0800 (PST) Received: from arm.com (usa-sjc-imap-foss1.foss.arm.com [10.121.207.14]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id EF5883F73C; Thu, 12 Nov 2020 03:17:50 -0800 (PST) Date: Thu, 12 Nov 2020 11:17:47 +0000 From: Dave Martin To: Li Qiang Subject: Re: [PATCH 0/1] arm64: Accelerate Adler32 using arm64 SVE instructions. Message-ID: <20201112111745.GS6882@arm.com> References: <20201103121506.1533-1-liqiang64@huawei.com> <20201105165301.GH6882@arm.com> <20201110104629.GJ6882@arm.com> <89a9bdcc-b96e-2f2d-6c52-ca44e0e3472c@huawei.com> <20201110160708.GL6882@arm.com> <484ad2c8-3905-fc98-237c-f7eb4045edbc@huawei.com> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <484ad2c8-3905-fc98-237c-f7eb4045edbc@huawei.com> User-Agent: Mutt/1.5.23 (2014-03-12) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20201112_061755_409108_1180769D X-CRM114-Status: GOOD ( 50.89 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: alexandre.torgue@st.com, catalin.marinas@arm.com, gaoguijin@huawei.com, colordev.jiang@huawei.com, luchunhua@huawei.com, linux-crypto@vger.kernel.org, mcoquelin.stm32@gmail.com, liliang889@huawei.com, will@kernel.org, davem@davemloft.net, linux-arm-kernel@lists.infradead.org, herbert@gondor.apana.org.au Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: base64 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org T24gVGh1LCBOb3YgMTIsIDIwMjAgYXQgMDM6MjA6NTNQTSArMDgwMCwgTGkgUWlhbmcgd3JvdGU6 Cj4gCj4gCj4g5ZyoIDIwMjAvMTEvMTEgMDowNywgRGF2ZSBNYXJ0aW4g5YaZ6YGTOgo+ID4+Pj4+ IAlhZGQgICAgIHpBLnMsIHBQL20sIHpBLnMsIHpYLnMgICAgICAgIC8vIHpBLnMgKz0gelgucwo+ ID4+Pj4+Cj4gPj4+Pj4gCW1zYiAgICAgelgucywgcFAvbSwgekoucywgekIucyAgICAgICAgLy8g elgucyA6PSB6Qi5zIC0gelgucyAqIHpKLnMKPiA+Pj4+Pgo+ID4+Pj4+IAltb3ZwcmZ4IHpCLCB6 QQo+ID4+Pj4+IAltYWQgICAgIHpCLnMsIHBQL20sIHpWLnMsIHpYLnMgICAgICAgIC8vIHpCLnMg Oj0gelgucyArIHpBLnMgKiBWCj4gPj4gSSBmb3VuZCB0aGUgYnVnIEkgZW5jb3VudGVyZWQgZWFy bGllciwgdGhhdCBpcywgdGhlIGNhbGN1bGF0aW9uIG9mIHpCIGhlcmUKPiA+PiBuZWVkcyB0byB1 c2UgcEEgd2l0aCBhbGwgZWxlbWVudHMgYWN0aXZhdGVkLiBUaGUgcmVhc29uIGlzIHRoZSBzYW1l IGFzIG15Cj4gPj4gcHJldmlvdXMgZ3Vlc3MsIGJlY2F1c2UgYWxsIGVsZW1lbnRzIG9mIHpBIHNo b3VsZCBiZSBpbnZvbHZlZCB3aGVuIGNhbGN1bGF0aW5nIHpCLgo+ID4+IEJlY2F1c2UgdGhlIG9y aWdpbmFsIGNhbGN1bGF0aW9uIGZvcm11bGEgaXMgbGlrZSB0aGlzLgo+ID4+Cj4gPj4gRm9yIGV4 YW1wbGU6Cj4gPj4gSW4gdGhlIGxhc3QgbG9vcDoKPiA+PiAJbGVmdCBieXRlIGlzOgkgIDMgfCAg IDQgfCAgXDAgfAo+ID4+IAl6QS5zIGlzOgkxMDAgfCAyMDAgfCAxMDAgfCAyMDAgKHN1bSA9IDYw MCkKPiA+PiAJcFAucyBpczoJICAxIHwgICAxIHwgICAwIHwgICAwIChPbmx5IGFjdGl2YXRlIHRo ZSBmaXJzdCAyIGNoYW5uZWxzKQo+ID4+Cj4gPj4gQXQgdGhpcyB0aW1lLCBpZiB0aGUgY2FsY3Vs YXRpb24gb2YgekIgb25seSB0YWtlcyB0aGUgZmlyc3QgMiBhY3RpdmUgZWxlbWVudHMsIHRoZSBk YXRhCj4gPj4gaXMgaW5jb21wbGV0ZSwgYmVjYXVzZSBhY2NvcmRpbmcgdG8gdGhlIGRlc2NyaXB0 aW9uIG9mIHRoZSBvcmlnaW5hbCBhbGdvcml0aG0sIHpCIGlzIGFsd2F5cwo+ID4+IGJhc2VkIG9u IHRoZSBzdW0gb2YgYWxsIHRoZSBhY2N1bXVsYXRlZCBieXRlcy4KPiA+IFllcywgeW91J3JlIHF1 aXRlIHJpZ2h0IGhlcmU6IHpYIGlzIHBhcnRpYWw6IG9ubHkgdGhlIGVsZW1lbnRzIHBQIGFyZQo+ ID4gdmFsaWQ7IGJ1dCBhbGwgZWxlbWVudHMgb2YgekEgYW5kIHpCIGFyZSBhbHdheXMgdmFsaWQu ICBJIHdhcyBmb2N1c2luZwo+ID4gdG9vIG11Y2ggb24gdGhlIGhhbmRsaW5nIG9mIHRoZSBwYXJ0 aWFsIGlucHV0IGJsb2NrLgo+ID4gCj4gPj4gSGVyZSB3ZSBjYW4gc2ltcGx5IGNoYW5nZSB0aGUg cHJlZGljdGlvbiByZWdpc3RlciB1c2VkIGluIHRoZSB0d28gc2VudGVuY2VzIHJlbGF0ZWQgdG8K PiA+PiB6QiB0byB0aGUgb25lIHRoYXQgaXMgYWxsIHRydWUgKGl0IGlzIHBBIGluIG91ciBjb2Rl KSwgbGlrZSB0aGlzOgo+ID4+IAltc2IgICAgIHpYLnMsIHBBL20sIHpKLnMsIHpCLnMgICAgICAg IC8vIHpYLnMgOj0gekIucyAtIHpYLnMgKiB6Si5zCj4gPiBBcmUgeW91IHN1cmUgYWJvdXQgdGhp cz8gIEluIGEgZmluYWwgcGFydGlhbCBibG9jaywgdGhlIHRyYWlsaW5nCj4gPiBlbGVtZW50cyBv ZiB6WC5zIGJleW9uZCBwUCB3aWxsIGJlIGxlZnRvdmVyIGp1bmsgZnJvbSB0aGUgbGFzdAo+ID4g aXRlcmF0aW9uLgo+IAo+IFllcywgSSBoYXZlIHZlcmlmaWVkIHRoaXMgY29kZSBhbmQgaXQgaXMg Y29ycmVjdC4gVGhlIHJlYXNvbiBpcyB0aGF0IGlmIHBQIGlzIHVzZWQgaGVyZSwKPiB0aGUgaW5h Y3RpdmUgZWxlbWVudHMgb2YgekIgd2lsbCBiZSBpZ25vcmVkIGluIHpYLCB3aGljaCB3aWxsIGNh dXNlIGRhdGEgbG9zcy4oSSB0aGluayBpdCBpcwoKWWVzLCB5b3UncmUgcXVpdGUgcmlnaHQuICBJ IHdhcyBmb3JnZXR0aW5nIGFib3V0IHRoZSAveiAoemVyb2luZykKc2VtYW50aWNzIGZvciB0aGUg bGQxYi4gIFRoaXMgbWVhbnMgdGhhdCB3ZSBnZXQgYXdheSB3aXRoIG5vdAppbmFjdGl2YXRpbmcg dGhvc2UgZWxlbWVudHMgaW4gdGhlIG1zYiBpbnN0cnVjdGlvbiwgc2luY2UgemVyb3MKbXVsdGlw bGllZCBieSB0aGUgZWxlbWVudHMgb2YgekogcmVtYWluIHplcm8uCgo+IGJlY2F1c2UgdGhlIHpC IGRhdGEgaXMgY292ZXJlZCBieSB0aGUgbXVsdGlwbGljYXRpb24gYW5kIGFkZGl0aW9uIHJlc3Vs dHMgb2YgelgsIHpBLCBhbmQgelYKPiB1c2luZyBtb3ZwcmZ4IGFuZCBtYWQuIEhhdmUgSSBnb3Qg dGhhdCByaWdodD8pIDopCgpZZXMsIEkgdGhpbmsgc28uCgo+IE9uIHRoZSBvdGhlciBoYW5kIHpY IHVzZXMgdGhlIHByZWRpY3Rpb24gcmVnaXN0ZXIgcFAveiB3aGVuIGxvYWRpbmcgZGF0YSwgdGhl IHZhbHVlIG9mIHRoZQo+IGluYWN0aXZlIGVsZW1lbnQgaXMgMCwgdGhlIGluYWN0aXZlIGVsZW1l bnQgaW4gelggd2lsbCBub3QgYWZmZWN0IHRoZSBmaW5hbCByZXN1bHQsIHRoZSBpbmFjdGl2ZQo+ IGVsZW1lbnQgaW4gekIgd2lsbCBiZSBkaXJlY3RseSBhc3NpZ25lZCB0byB0aGUgaW5hY3RpdmUg ZWxlbWVudCBvZiB6WCBlbGVtZW50Lgo+IAo+IFRoZW4gaW4gdGhlIG5leHQgaW5zdHJ1Y3Rpb24s IGl0IHdpbGwgYmUgYWRkZWQgdG8gekIgYWxvbmcgd2l0aCB6WC4KClllcy4KClRoaXMgbWlnaHQg YmUgcGFydCBvZiB0aGUgcmVhc29uIHdoeSB0aGUgYXJjaGl0ZWN0cyBkZWNpZGVkIHRoYXQgU1ZF CmxvYWRzIHplcm8gdGhlIGluYWN0aXZlIGVsZW1lbnRzIGluc3RlYWQgb2YgbGVhdmluZyB0aGVt IHVuY2hhbmdlZC4KCj4gCj4gPiAKPiA+IFRoaXMgbWlnaHQgcmVxdWlyZSBhIGJpdCBtb3JlIHRo b3VnaHQgaW4gb3JkZXIgdG8gZ2V0IHRoZSBmaW5hbCBibG9jawo+ID4gaGFuZGxpbmcgY29ycmVj dC4KPiA+IAo+ID4+IHRyYWlsbG9vcDoJCQkvLyBMYXN0IGN5Y2xlIGVudHJhbmNlCj4gPj4gICAg ICAgICBjbnRwICAgIHg2LCBwMSwgcDAucwkvLyBHZXQgYWN0aXZlIGVsZW1lbnQgY291bnQgb2Yg bGFzdCBjeWNsZQo+ID4+ICAgICAgICAgY3B5ICAgICB6Vi5zLCBwMS9tLCB3NgkvLyBTZXQgelYg dG8gdGhlIGFjdHVhbCB2YWx1ZS4KPiA+IE5vdGUgdGhhdCB5b3UgY2FuIGFsc28gd3JpdGUgIm1v diIgaGVyZSwgYnV0IEknbSBub3Qgc3VyZSB3aGljaCBhbGlhcyBpcwo+ID4gcHJlZmVycmVkPgo+ ID4+IGxvb3A6CQkJCS8vIENvcmUgbG9vcCBlbnRyYW5jZQo+ID4+ICAgICAgICAgbGQxYiAgICB6 WC5zLCBwMC96LCBbeDFdCj4gPj4gICAgICAgICBpbmN3ICAgIHgxCj4gPj4KPiA+PiAgICAgICAg IGFkZCAgICAgekEucywgcDAvbSwgekEucywgelgucwkvLyBUaGUgY2FsY3VsYXRpb24gb2YgekEg c3RpbGwgbmVlZHMgdG8gdXNlIHAwCj4gPj4gICAgICAgICBtc2IgICAgIHpYLnMsIHAxL20sIHpK LnMsIHpCLnMJLy8gQ2hhbmdlIHAgcmVnaXN0ZXIgaGVyZQo+ID4+ICAgICAgICAgbW92cHJmeCB6 QiwgekEKPiA+PiAgICAgICAgIG1hZCAgICAgekIucywgcDEvbSwgelYucywgelgucwkvLyBDaGFu Z2UgcCByZWdpc3RlciBoZXJlCj4gPiBBcyBkaXNjdXNzZWQgYWJvdmUsIGFyZSB5b3Ugc3VyZSB0 aGlzIGlzIGNvcnJlY3Qgbm93PwoKSSB0aGluayB3ZSd2ZSBhZ3JlZWQgdGhhdCBpdCBpcyBjb3Jy ZWN0LgoKVGhpbmtpbmcgYWJvdXQgdGhlIGNvZGUgZmxvdywgSSB0aGluayB0aGUgaW5pdGlhbGlz YXRpb24gb2YgelYgaXMKc2xpZ2h0bHkgd3Jvbmc6IGZvciB2ZXJ5IHNob3J0IGRhdGEsIHRoZSBm aXJzdCBibG9jayBtYXkgYmUgc2hvcnRlciB0aGFuClZMLgoKSSB0aGluayB0aGlzIGlzIGVhc2ls eSBzb2x2ZWQgYnkgZ2V0dGluZyByaWQgb2YgdGhlIGNvbnN0YW50CmluaXRpYWxpc2F0aW9uIGZv ciB6ViBhbmQgcmVtb3ZpbmcgdGhlIGJyYW5jaCB0aGF0IHNraXBzIHRoZSBDTlRQIGNvZGUKd2hl biBlbnRlcmluZyB0aGUgbG9vcCBmb3IgdGhlIGZpcnN0IHRpbWUuICBUaGF0IHdheSwgelYgZ2V0 cwppbml0aWFsaXNlZCB0byB0aGUgY29ycmVjdCB0aGluZyBvbiBlbnRlcmluZyB0aGUgbG9vcCwg aXJyZXNwZWN0aXZlIG9mCndoZXRoZXIgd2UgaGF2ZSBhIHdob2xlIHZlY3RvciBvbiB0aGUgZmly c3QgaXRlcmF0aW9uLgoKTm90ZSwgdG8gc3F1ZWV6ZSBtYXhpbXVtIHBlcmZvcm1hbmNlIG91dCBv ZiB0aGlzLCB5b3Ugc3RpbGwgcHJvYmFibHkKd2FudCB0byB1bnJvbGwgdGhlIGxvb3AgYSBmZXcg dGltZXMgc28gdGhhdCB5b3UgY2FuIHNjaGVkdWxlIHVzZWZ1bCB3b3JrCmluIGJldHdlZW4gZWFj aCBsb2FkIGFuZCB0aGUgY29tcHV0YXRpb25zIHRoYXQgZGVwZW5kIG9uIGl0LgoKPiA+PiBzdGFy dDoKPiA+PiAgICAgICAgIHdoaWxlbG8gcDAucywgeDEsIHhMaW1pdAo+ID4+ICAgICAgICAgYi5s YXN0ICBsb29wCQkvLyBUaGUgY29uZGl0aW9uIGZvciB0aGUgY29yZSBsb29wIHRvIGNvbnRpbnVl IGlzIHRoYXQgYi5sYXN0IGlzIHRydWUKPiA+PiAgICAgICAgIGIuZmlyc3QgdHJhaWxsb29wCS8v IElmIGIubGFzdCBpcyBmYWxzZSBhbmQgYi5maXJzdCBpcyB0cnVlLCBpdCBtZWFucyB0aGUgbGFz dCBjeWNsZQo+ID4+Cj4gPj4gICAgICAgICB1YWRkdiAgIGQwLCBwMSwgekEucwo+ID4+ICAgICAg ICAgdWFkZHYgICBkMSwgcDEsIHpCLnMKPiA+Pgo+ID4+ICAgICAgICAgbW92ICAgICB4MTIsIHYw LjJkWzBdCj4gPj4gICAgICAgICBtb3YgICAgIHgxMywgdjEuMmRbMF0KPiA+IFRoZSAiMiIgaGVy ZSBzZWVtcyBub3QgdG8gYmUgcmVxdWlyZWQgYnkgdGhlIHN5bnRheCwgYWx0aG91Z2ggaXQncwo+ ID4gaGFybWxlc3MuCj4gCj4gWWVzIEkgZGVsZXRlZCBpdC4KPiAKPiA+IAo+ID4+ICAgICAgICAg YWRkICAgICB4MTAsIHgxMCwgeDEyCj4gPj4gICAgICAgICBhZGQgICAgIHgxMSwgeDExLCB4MTMK PiA+PiAgICAgICAgIGFkZCAgICAgeDExLCB4MTEsIHgyCj4gPiBJZiB4MTAgYW5kIHgxMSBhcmUg dXNlZCBhcyBhY2NtdWxhdG9ycyBieSB0aGUgY2FsbGVyLCBJIGd1ZXNzIHRoaXMgd29ya3MuCj4g Cj4gWDEwIGFuZCBYMTEgYXJlIHBhcnQgQSBhbmQgcGFydCBCIG9mIHRoZSBpbml0aWFsIHZhbHVl IG9mIGFkbGVyMzIgcGFzc2VkIGluIGJ5IHRoZSBjYWxsZXIuCgpSaWdodCwgdGhhdCBtYWtlcyBz ZW5zZS4KCj4gCj4gPiAKPiA+PiAgICAgICAgIG1vZDY1NTIxICAgICAgICAxMCwgMTQsIDEyCj4g Pj4gICAgICAgICBtb2Q2NTUyMSAgICAgICAgMTEsIDE0LCAxMgoKTm90ZSwgY2FuIHlvdSByZXBs YWNlIHRoZXNlIHdpdGggdWRpdj8KCldoaWxlIHVzaW5nIG11bCBtaWdodCBiZSBzbGlnaHRseSBj aGVhcGVyIHRvIGFjaGlldmUgdGhpcywgaXQgbWFrZXMgdGhlCmNvZGUgbW9yZSBjb21wbGV4IGFu ZCB3aWxsIGhhdmUgYSBuZWdsaWdpYmxlIGltcGFjdCBvbiB0aGUgb3ZlcmFsbApjb3N0Li4uCgpT bywgZG9lcyBzb21ldGhpbmcgbGlrZSB0aGlzIHdvcms6CgoJbW92CXgzLCAjNjU1MjEKCXVkaXYJ eDQsIHgxMCwgeDMKCXVkaXYJeDUsIHgxMSwgeDMKCW1zdWIJeDEwLCB4NCwgeDMsIHgxMAoJbXN1 Ygl4MTEsIHg1LCB4MywgeDExCgo+ID4+ICAgICAgICAgbHNsICAgICB4MTEsIHgxMSwgIzE2Cj4g Pj4gICAgICAgICBvcnIgICAgIHgwLCB4MTAsIHgxMQo+ID4+ICAgICAgICAgcmV0Cj4gPj4gLS0+ OC0tCj4gPj4KPiA+PiBBZnRlciB0aGlzIG1vZGlmaWNhdGlvbiwgVGhlIHRlc3QgcmVzdWx0cyBh cmUgY29ycmVjdCB3aGVuIHRoZSBkYXRhIGxlbmd0aCBpcyBsZXNzIHRoYW4gYWJvdXQgOCBLYnl0 ZSwKPiA+PiBwYXJ0IEEgd2lsbCBzdGlsbCBiZSBjb3JyZWN0IGFmdGVyIDhLLCBhbmQgYW4gb3Zl cmZsb3cgZXJyb3Igd2lsbCBvY2N1ciBpbiBwYXJ0IEIuIFRoaXMgaXMgYmVjYXVzZSBBCj4gPj4g b25seSBhY2N1bXVsYXRlcyBhbGwgdGhlIGJ5dGVzLCBhbmQgdGhlIGFjY3VtdWxhdGl2ZSBhY2Nl bGVyYXRpb24gb2YgQiBleHBhbmRzIGZhc3RlciwgYmVjYXVzZSB0aGUKPiA+PiBhY2N1bXVsYXRp dmUgZm9ybXVsYSBvZiBCIGlzOgo+ID4+IAlCID0gKDEgKyBEMSkgKyAoMSArIEQxICsgRDIpICsg Li4uICsgKDEgKyBEMSArIEQyICsgLi4uICsgRG4pIChtb2QgNjU1MjEpCj4gPj4gICAgICAgICAg ICA9IG7Dl0QxICsgKG7iiJIxKcOXRDIgKyAobuKIkjIpw5dEMyArIC4uLiArIERuICsgbiAobW9k IDY1NTIxKQo+ID4+Cj4gPj4gSWYgd2UgdGFrZSB0aGUgYXZlcmFnZSB2YWx1ZSBvZiBEeCB0byAx MjggYW5kIG4gdG8gODE5MjoKPiA+PiAJQiA9ICgxICsgMiArIC4uLiArIDgxMjkpICogMTI4ICsg ODE5Mgo+ID4+IAkgID0gNCwyOTUsNDk5LDc3NiAoMzJiaXQgb3ZlcmZsb3cpCj4gPj4KPiA+PiBT byBJIHRoaW5rIHRoZSAzMi1iaXQgYWNjdW11bGF0b3IgaXMgc3RpbGwgbm90IGVub3VnaCBmb3Ig cGFydCBCIGhlcmUuIDopCj4gPj4KPiA+PiAtLSAKPiA+PiBCZXN0IHJlZ2FyZHMsCj4gPj4gTGkg UWlhbmcKPiA+IFRoYXQgbWFrZXMgc2Vuc2UuICBJIGhhZG4ndCB0cmllZCB0byBjYWxjdWxhdGUg dGhlIGFjdHVhbCBib3VuZC4KPiA+IAo+ID4gSXQgbWF5IGJlIHdvcnRoIHRyeWluZyB0aGlzIHdp dGggNjQtYml0IGFjY3VtdWxhdG9ycy4gIFRoaXMgd2lsbAo+ID4gcHJvYmFibHkgc2xvdyB0aGlu Z3MgZG93biwgYnV0IGl0IGRlcGVuZHMgb24gdGhlIHJlbGF0aXZlIGNvbXB1dGF0aW9uIC8KPiA+ IG1lbW9yeSB0aHJvdWdocHV0IGV4aGliaXRlZCBieSB0aGUgaGFyZHdhcmUuCj4gCj4gSWYgYSA2 NC1iaXQgd2lkZSB2ZWN0b3IgcmVnaXN0ZXIgaXMgdXNlZCwgZm9yIG1vc3Qgc2NlbmVzIHdoZXJl IHRoZSBhbW91bnQgb2YgZGF0YSBpcyBub3QgcGFydGljdWxhcmx5IGxhcmdlLAo+IGlzIGl0IHdh c3RlZCBtb3JlIHZlY3RvciByZXNvdXJjZXM/CgpZZXMgOikKCkRlcGVuZGluZyBvbiB0aGUgYWxn b3JpdGhtLCB0aGlzIG1pZ2h0IGJlIGEgYmV0dGVyIHRyYWRlb2ZmIGlmIGl0IG1lYW50CnRoYXQg dGhlIGRhdGEgY291bGQgYmUgcHJvY2Vzc2VkIGluIGxhcmdlciBjaHVua3MuICBJIHN1c3BlY3Qg dGhhdCB0aGUKdHJhZGVvZmYgaXMgdW5mYXZvdXJhYmxlIGluIHRoaXMgcGFydGljbHVhciBjYXNl IHRob3VnaCAtLSBidXQgSSBoYXZlbid0CnRyaWVkIGl0LgoKPiBNYXliZSB3ZSBjYW4gYWxzbyB0 cnkgdG8gdXNlIDE2LWJpdCB3aWRlIHZlY3RvciByZWdpc3RlcnMgdG8gbG9hZCBkYXRhIGFuZCBj YWxjdWxhdGlvbnMsCj4gYW5kIGFjY3VtdWxhdGUgdGhlbSBpbnRvIHRoZSBzY2FsYXIgcmVnaXN0 ZXIgeG4gYmVmb3JlIG92ZXJmbG93LCBqdXN0IGxpa2UgbXkgb3JpZ2luYWwgcGF0Y2gsCj4gYnV0 IEkgY2FuIHRyeSB0byB1c2UgYXNjZW5kaW5nIG9yZGVyIHRvIGNoYW5nZSB0aGUgcHJvY2Vzc2lu ZyBvZiB0aGUgbGFzdCBsb29wIEJlIG1vcmUgZWxlZ2FudC4KClBlcmhhcHMuICBCdXQgSSBhc3N1 bWVkIHRoYXQgMTYtYml0IGVsZW1lbnRzIHdvdWxkIG92ZXJmbG93IG11Y2ggdG9vCmZhc3QgdG8g YmUgcHJhY3RpY2FsLiAgSnVzdCBtdWx0aXBseWluZyB6WCBieSB6SiBvbmNlIGNhbiBwcm9kdWNl CmVsZW1lbnQgdmFsdWVzIHVwIHRvIDB4ZmUwMSBpZiBWTCBpcyAyNTYgYnl0ZXMuCgpEaWQgeW91 IGhhdmUgc29tZSBpZGVhIGZvciBob3cgdG8gbWFrZSB0aGlzIHdvcms/CgpJdCBtYXkgYmUgcG9z c2libGUgdG8gZG8gMTYtYml0IG11bHRpcGxpZXMgd2l0aCAzMi1iaXQgYWNjdW11bGF0aW9uLgpT VkUyIGhhcyBzb21lIE5FT04tc3R5bGUgbWl4ZWQtd2lkdGggbXVsdGlwbHktYWNjdW11bGF0ZSBp bnN0cnVjdGlvbnMKdGhhdCBjYW4gYWNoaWV2ZSB0aGlzIHNvcnQgb2YgdGhpbmcgZGlyZWN0bHks IGJ1dCBpbiBTVkUoMSkgSSB0aGluayAKeW91IHdvdWxkIGhhdmUgdG8gYnJlYWsgdGhlIG11bHRp cGx5LWFjY3VtdWxhdGVzIHVwLiAgU2F5OgoKCW11bAl6WC5oLCBwUC9tLCB6WC5oLCB6Si5oCglz dWIJelgucywgcFAvbSwgekIucywgelgucwoKd2hpbGVsbyBwUC5zIHNob3VsZCBnZW5lcmF0ZSBh IHByZWRpY2F0ZSB3aXRoIG9kZCAuaCBlbGVtZW50cyBpbmFjdGl2ZSwKYW5kIGxkMWIgelgucywg cFAveiwgLi4uIHdpbGwgbWFrZSBzdXJlIHRob3NlIGVsZW1lbnRzIGFyZSBhbGwgemVyb2VkIGlu CnhYLmguCgpJJ20gbm90IHN1cmUgdGhpcyB3b3VsZCBiZSBmYXN0ZXIgdGhhbiBhIHNpbmdsZSAz Mi1iaXQgbXNiLCBzaW5jZQptdWx0aXBseS1hY2N1bXVsYXRlcyBhcmUgbGlrZWx5IHRvIGJlIGhl YXZpbHkgb3B0aW1pc2VkIGluIHRoZSBoYXJkd2FyZSwKYnV0IHlvdSBjb3VsZCB0cnkgaXQuCgo+ ID4gCj4gPiBJIHRoaW5rIHRoZSBjb2RlIGNhbid0IGJlIGJ1bGxldHByb29mIHdpdGhvdXQgYnJl YWtpbmcgdGhlIGlucHV0IGludG8KPiA+IGNodW5rcyBhbnl3YXksIHRob3VnaC4KPiAKPiBJIGRv bid0IHF1aXRlIHVuZGVyc3RhbmQgd2hhdCBpdCBtZWFucyBoZXJlLiBEb2VzIGl0IG1lYW4gdGhh dCB0aGUgaW5wdXQgYnl0ZXMgYXJlIHJlYWQgaW50byB0aGUgdmVjdG9yIGluCj4gYmxvY2tzIGZv ciBjYWxjdWxhdGlvbiAodGhpcyBpcyBob3cgaXQgaXMgZG9uZSBub3cpIG9yIHRoZSBpbnRlcm1l ZGlhdGUgcmVzdWx0cyBhcmUgc3RvcmVkIGluIGRpZmZlcmVudCBlbGVtZW50cwo+IG9mIHRoZSB2 ZWN0b3IgaW4gYmxvY2tzIGR1cmluZyB0aGUgY2FsY3VsYXRpb24gcHJvY2Vzcz8gOi0pCgpJIG1l YW4sIHlvdSBsaW1pdCB0aGUgbnVtYmVyIG9mIGl0ZXJhdGlvbnMgb2YgdGhlIGNvcmUgbG9vcCBz byB0aGF0Cm92ZXJmbG93IGRvZXNuJ3QgaGFwcGVuLiAgWW91J3JlIGFscmVhZHkgZG9pbmcgdGhp czsgSSBqdXN0IHdhbnRlZCB0bwogbWFrZSB0aGUgcG9pbnQgdGhhdCA2NC1iaXQgYWNjdW11bGF0 b3JzIHByb2JhYmx5IGRvbid0IHNvbHZlIHRoaXMKcHJvYmxlbSwgZXZlbiB0aG91Z2ggaXQgd2ls bCB0YWtlIGEgdmVyeSBsYXJnZSBudW1iZXIgb2YgaXRlcmF0aW9ucyB0bwpjYXVzZSBhbiBvdmVy Zmxvdy4KClVubGVzcyBBZGxlcjMyIHNwZWNpZmllcyB0aGUgbWF4aW11bSBsZW5ndGggb2YgdGhl IGlucHV0IGRhdGEgbm90IHRvCmV4Y2VlZCBzb21lIHZhbHVlLCBpdCBjb3VsZCBnbyBvbiBmb3Jl dmVyIC0tIHNvIG92ZXJmbG93IGJlY29tZXMKaW5ldml0YWJsZS4KCkNoZWVycwotLS1EYXZlCgpf X19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXwpsaW51eC1hcm0t a2VybmVsIG1haWxpbmcgbGlzdApsaW51eC1hcm0ta2VybmVsQGxpc3RzLmluZnJhZGVhZC5vcmcK aHR0cDovL2xpc3RzLmluZnJhZGVhZC5vcmcvbWFpbG1hbi9saXN0aW5mby9saW51eC1hcm0ta2Vy bmVsCg==