矢量化没有提供预期的加速
Vectorization not providing expected speed up
我在 .NET 4.7.2 上使用 System.Numerics.Vector 很开心。作为第一次尝试,我编写了一个基本函数来识别 ASCII 字符串中是否有空格。我实现了三个版本的功能:
- LINQ,
- 经典 for 循环和
- 矢量化版本 (SIMD)。
我惊讶地发现矢量化版本比经典的 for 循环慢得多。
BenchmarkDotNet=v0.12.1, OS=Windows 10
Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
[Host] : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
Job-AWDTWU : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
Jit=RyuJit Platform=X64 Runtime=.NET 4.7.2
| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------------------- |----------:|---------:|----------:|----------:|------:|--------:|------:|------:|------:|----------:|
| HasWhiteSpacesWithSimd | 35.99 us | 1.038 us | 2.928 us | 35.14 us | 0.17 | 0.02 | - | - | - | - |
| HasWhiteSpacesWithLoop | 17.00 us | 0.335 us | 0.586 us | 17.10 us | 0.08 | 0.00 | - | - | - | - |
| HasWhiteSpacesWithLinq | 220.59 us | 4.408 us | 10.896 us | 220.55 us | 1.00 | 0.00 | - | - | - | 966 B |
下面是我实现的矢量化版本。
public static class StringExtensions
{
static Vector<byte> spaces = new Vector<byte>(Convert.ToByte(' '));
public static bool HasWhiteSpaces(this string s)
{
const int registersize = 32;
if (s == null)
{
return false;
}
int pos = 0;
byte[] bytes = ArrayPool<byte>.Shared.Rent(32);
while (pos < s.Length)
{
Encoding.UTF8.GetBytes(s, pos, registersize, bytes, 0);
Vector<byte> v = new Vector<byte>(bytes);
bool foundAnySpaces = Vector.EqualsAny(v, spaces);
pos += registersize;
if (foundAnySpaces)
{
ArrayPool<byte>.Shared.Return(bytes);
return true;
}
}
ArrayPool<byte>.Shared.Return(bytes);
return false;
}
}
我是不是做错了什么?在这一点上,我假设经典的 for 循环版本由于 CPU 缓存而更快,但我原以为我会通过矢量版本获得适度的加速。
这是带有基准测试的完整代码。
using System;
using System.Buffers;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Security.Policy;
using System.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Validators;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
BenchmarkRunner
.Run<Simd>(
DefaultConfig.Instance
.AddJob(Job.Default.WithRuntime(ClrRuntime.Net472).WithPlatform(Platform.X64).WithJit(Jit.RyuJit))
.AddValidator(ExecutionValidator.FailOnError));
}
}
[MemoryDiagnoser]
public class Simd
{
public string[] lines = new[] {
@"CVN7OINF&KN4QTV/WZE1SHG/TLXON2S985XG73RBH3BO\&9/FDL/7PQNPVV6P9AC/W0E&TK\AG&GSX14PZIJQVBSPJ3LHXZL3\ROL4\Z6N91PK8564R214YOVH222PU1PTFMTY1VPDZMDFO\RPG9W\NC6DCJ98WTG17OZUK6AFOV2IEWN4TOJXEQGDTPVSZUTFFOLAM/FN8RX4MX&S8FPHKWXQHVA8KVT7CXC2LNRVJ81Z6P39QDXTEL7W48539JCN2UJHU06\O7/W55ERH\&232T\QV1Y&5O1E0BOH8C6LNS27L&8O\&\&BL3\H&VSIRF32KL8GRQK3DEW36H/A2E1CN9FE7DO/KY77HBUXS5VV2KHZPIN4YRTNR0POG4MNBNTSK2V4ZMV/WFNC1S1Z2WL5FTQUZGR0SHUP42P0ZVFL9V3LMMZ0DZXSB0M3MBFS87ROY\L&DBAHRA9W3EHMU3X6WBNDPYOXQZPBDP0OB0XCZQAB43AH75\FKY4WXIWRZP45X7SOR5L7GUGGBMLZYG3X0J4SXD35DFPKZIQ/KZ3BUE&2SYVL9/6SZGENDA3NCS3AF8U68OO&Q2DWKB&&VS9FL9YSDC6J8P\BN\WWE1PVV7C9DUDBA45XWX2JKB26UFDA3CJLRQ86CNXR61PWIEXOR2JNMC&WAQ3BGBL5XX9\UJALPWYG739&QOXTBDE56TNG05UNKGHYHY7I2\2Q61JU4Y4Q54TTEEA87XWBK91VK44UP4DFOOA5DZ8H2/RP0EDT6M7NO1G/A1JA6KAB0OF2DI4H2PLNRM8G0L1C923ZID4PQ8OS9Q1M&NPXV0Y&P5S15CMUV\F\XSUARO47B6QAXVHM8EUIE4KPXDWNV6/\L21T6PGG84\WOSDJ8AZRQ976HFPN5RLH8S1870TT/ONN51BF&NRVHSUP87L0A5OQS3083IPITGTCVTBTEKNRA2AQ\M&AO5SE&97CAFO4\ICB&R7O65W3S9Q23K/RIO700OCYZ",
@"&S&8WT40&QTSYHWJ2ZDTFL3H9VWOONXOI27MX78PYB46R&XHKR/2&FU014&A/PMY6EK8NKY8307DU/29/OE9Q8PCIGX578RI2G&N227A5C\LLQG4CDCVLPIH0GZ5B8IYOO/OGIUDEO9D34&63459/M/BYVB0N&BDC0C56097BIL7BXQ9G6CJCM1BQ92YH63EN6BD1H&C7AD&AEEUT/4A2\BP9\L0ISHUHWNI&7AOES&AM91UCMJHV6LE05CEWLZJ6W5R39UZ9P8K&ACAJ3Y8J&\NLIVG495652G2EK3F4WKG/AFZ2C7503A6YRFVON8AXCSK6M8\ASEZ25QLD8R1B&GB1MEZFH3Q0KW8U85PH95HZOE6B6ST9H&X9QVTIJ6511&SIU3ICBUFH\PNIKXM2KTTK\&EMMG/C&S\OZXUCKQ706Q/AIL/YUCRHTHKVZ837WCHTR\V0DJS7Z6RVCEDAJMV9B38SN\QO0&D4IRVJ3KUKXXV022TU52YKTKR0DCNE5DHZ2ZMYV6KKLRII2YS8W/O6K\&7G0/PRUP8/DP7&\SZSI\AS8N1Y/UJK9PNY00XBO54BMKZIX9XR1NB&&PKMI4U&GYA1BJML8YEQG\FY0TAA/5WWNOZKPK6XK481J\GOXLWDJY5AKZZ23UCNBRN0XB8X5TFPDQO2MZQYISM1VY&2YD732UZ4XT4VQ\L2TQ/7L9PDDRFVEZF\BF&1ZO0V3WF677IKHXIE0FR113ZKPE0\N5TK\WDF3OE14WJIJ8NURAK91LA81PGZ9GSCN/LYTCNMB39EUQBU3FUMVXW0WIQOIR4XDH8LW2BO0\O8OKOZ84ZGU3OXBKY&DW\MBNV2/ADFZW1XM16GAWWA//0E/&13208MAB6B1Y180UT/C3LNRS&TA/OE0R5\LNQPXK75RO70MQQ2BG0OMK1OMC02OJ63WNEUJ0GBSYAXZMX[=12=]/PZK/AFKMCUWERIVDD&M9SO&Y80JD2&S1CQ6GTZM\J/XYROH5CVIYZ",
@"4RBZZBM9GXDC7BBOOXRZOZV4OGUTQBH36CLU6X&BDMUVWMGR0/4\LF8KKSU6SFPMI43CV736ZMWJJ6WHN&OJ&84GCVJODGW/9IM4VD85G/M\VZAR8MST3GMNAX&AXP3S3YMBT4ZJDVDBV6XQU5S30CH38\E8I3G6I/N&/E0JPIDK4G&WS5/&50RVGU&0FHNM82XZCV7ODR0&0XHX\VPQ6GAVT56QE&EH73PCWMT//V9OAR8VNO1W4/S11CGK2RKDMSE9HEBYBSSLKZUB/KC2KUQ/L1NTGJITL6BUN\NJNDUMSHRBUENRPV55CHXT3US5K&AQYA1OHADSEKM\B93E3AJSGN7S5Y2BSHAQUQOUVGY4TJRWQ9T7JQPUUXCOWWKC&/J9RYUIVWPRUR7YBJH5UY/WBA83SHWBU92W&VE4OLMZA/AD3RMNOSUO&Z8Q243OAN/X2KYSEPQJLKWDA5&A7J0BPNWM00CXU\Z0APNS57I\BKC2D4Q/42T408IO1M5QN61NX9CYRTIAA2AFL7I8KF65R8&EG&4TB5XIV1EH15SKTT3DC7D/GI&9929\RS22&HE5WX2AGRZWL\EBJC9/PEZPIZ4PL3N&V4TW6DUSED31VQX/X71PW4M7V2W/5M2QE0BTRVHGVQ5MN/65C64QC\Q3SZAETW05NNX8PDTCZU6F\AUY848\VLNFKKB5UD0A\AN\P\N13UFK4REPJ111JC&RXEB0UW77P\CTK/O9Y6U5AASX0F6\JB39B8NL9ZHG0K76PYELN5DQUGQXZRAO29XNHFSPWD&\ZNF3FZIBBUYR\NO7R3ZSZ5R4ZUZJG12J5F4GB0SAI\MIKGP74X/6RTM69OEY&&8M5OZ6WI64LYK0SITTE4RV495L5/JZV7AJC&P9TWLV4FV5JYO07YTHUMV8WNAY\GIQYBXS6W&VT94ZO&CHVW5/O513RTNGVZXX9EGIA87KY/1YU9UWL5CPOKC6M7BMJ6&7LH2J56H01UMQEDIV&37",
@"3WIJYBN9F7VB5/6NNHK4SYP06\Y2JZSNT\JKC\DIS/B5GTTTK38O1&PEHVP0PXZTOHU60WKPDCLUWWTNSFSS4EYUWECUWQ57KVQ\Z50STKZ07VXBBHKFG2KWAKWT250KRKBGVP5M4&K6&71WSSUIU1D5GP/PJH30XOIXTRTZO\OHRQWGV&BJLR22GI&FRQCXJXJXYECA&86VN9O2547JFTOFYSQKRNH/6G\UQ9AKPYGPK7KNZW5R3IE\F05WZ08ZW&UV6JQMFI&TSDGPHAVPDMGXBAP2ERY22U5LN1TPFSLUJXTCUPOYFSWJ59T670I1XJ4\K8CTTFJXAYORTMI2C&XJ/VSRH0URKX/&6V4ZN8F&J&JGVCMUSSYXZUA1PYM5X4NQ1OX/VWPH6XA\MM8ENA&5\MMMVCJ1WNPRZ5SGSO&9CR4CTCOD2HRX5VROBLPTN0YSHWMU72Z\AD2UVK5S0F&O95YEODEG&TWP6L8/37J&VSW25954S/5H1JWP/HF3XS&UUM1KO8169&6QI9LRKN1B0O0W1S&V1TPCSCHTIVPWI&K1PGGA91SK4/6FZEV88GEQX4/G15I2/E61D&GVM\YAAFLUIC7D&U0C87EYI&MES3NZEFBZ/AW/UDPRSQ\Z\E2QQ46J7VNMZUVJ5YQDAHG&/3U4RZF5BZGNB/JMM55P0JKAVGZ7&8Z4SZJB4HPVLANHI7OD4HO3L0SUJLAL5GAPOKRWCKBXAF\KZN/4S8ERPIR4G24SHD2E&/Q5ATG32G2I78OI5/CWAG60PNTWQ9P7K1VAO07XKYSKCE&K5CQ\YD2P0AXN648/GNN6FCRLO1WYRTXRRZX46299YKHX0LZTHB0U3FF3YFX/UE\HQF9HHDDRRRH777XCCCRP5C1LT6G0F\OUMAHVPSMD/JCM\K83VU8S0VONRX0N/PLTC0V7ZCZX3NSV&OMJ\PFYD964Y6D44&FU\WKK2ADS7K1MC5NCKROUK0PF63J64H\XPECT/L035I",
@"U15TATNXYKKGEQKT&S/EEI/\I/RJW9X/MCQN\ORHW0NIAYUGAG4MKPWXVCKQGO0NWGE9N/VXB3UR81\XPKIQFKZ/T648DBAIA&Z6UY5CXGLU7F26E0A8FJIMTGQUFZT&2MR8CED4SG6&\FCNEQBFC33MMNIK9/ZM5U163&XJP&QJNOECQH8D\WK0F243VHJ9MZMVZKI5552CNU&\JG72CVOIKA1AH70H3T91BWPF\CLF7HNX36UPNT63LEKZWHX\EVM6XL9Z313&KIODZDKONL7J0GQ/L3V4SMAL8UAS97YY26TC2G&T/IY60CFR8&O&F&U/ICIFD4STZIU60NHE4C6J1GY5OVW/SZS3MV70QF3FHRVM4U5JIDGLIBRP4UHVA&33UETTG/Z0SW&GKB4CEJQOWAM6JVC9/IEH145ZBLCKRT5ZCKF22FQ3WOHT50KX832JR4STJEB6GF/DH03\QMG55OYMWL7NASP13WHK5YTXEWXQQDLE9LHVW/RDFF9/K0513JMYTTG46V1J3I8TA2R2K6E6EDFZ2VNQ38ZH3ZYQFP2BIIN9JQ/VJDQ9FTUPNTBLHKS8W12NDBX7ECX93JQMX5H0R3CKFJCYOQ6/2RNU0XRITV5C8XZED21PD4Q6ZRI7\T0J0GL88ZAN&H9/&PUW\VZ2Q7/BU8JOXJUCE6IQOIHD0CEXU8ZC0K&Q7/55JJO&PY22Z76GHEI2NVBN3NUZJG1MJEHHAPHE7I0CNO/0CS7WCKCL8RC9223J/QSVZZF59D8F8&AOP7W3MEJ&B8LWNLOERRF98PAQMCZ&O/Q9R0T8F&95GTU4NWRY230R7DT&6GQJSKXESOEZ4T&RUM3O8IC3XAJYJ\CNGTB\W0N88QM&R57J4J/UNEEXE0ZRA&7UM4SKRA87TS9DL5GA6AAUACOR78B888V4Z0MW54NDVSYZ0BP6K&G7T54Q8&GA6C&X9FQXSXICZ/\UR235SHY821L79905XNKTTA3VY4N04DHV6J&GJNU",
@"YRD7I6V1W9QRM0SAQ\HH06/EYT3AZ9UVK6YBQGV2CD44NZ88OIVHBG64U&J1DUBZP7GTBRXKQSEXCF3&Y7ZQOMUE&6TQ/6ZUBEPSSP6/YL4VBJ2PIJDI8YLCNCTI/GMX6XVLTJB25CU\C3EEI03QZQ5MFP8Y&R\H2R04Z937HG5JUOA2D5\Z7P\FFPFDNP2ODNIYDNSL98JSXW54PFUGTMNMTUYJ4ZT4QRGGFOZ3NZ3\GSVWXO1I8V84A9FW1JUJPRCGQYYBT466WOFB&CYQ\L87VPGJJDBEETV1POG&2Z1E2BIY3EXZXEKDWHXBSP4Q221C6RYX9Y0LW4EUHUTESPTAIRFH3FUN8LOAMF5LT&3\Q&U4CD6/9Z/NI17OLQ64EMQKPEHB1HYTZUXJ/NF0LWRIOB5YLRACGEVJOJ1AR11DXQ/LGTV7I9OMV3KGWM00S11&G4TN2H/NEU0AC4&SLJMMAZNB\VREBAY92\EPAIEA&BIBDKE5NHOIOO\URROH25MD93KDZXSDFMN&RLQZ36ZPVOAX\V6/LG2EFM&AF31KDCB&DFT03DBSRTH9DBY/KIAGKMGY1PTAEOMTMAU5CGGIEJ0YEC/EE4A8B723\OWBNCH1WCT67DC5CAYVTYSP9MNRSSL37GI4YD8XRQT8XL/96I42FQOM9HFB12JD33KH&EADDFW4XPRYJ1WYQ588Q1HPE7MJBVB5XEMLGMQUYKE&PHEV8AO3BJEP93S9LGQCI8\TDT1WARIYWH&/24NAHL4N&/PQ7TIS7C4TIYROL52WAT513UGU5P8/EXTFEK2UI33UQT2EMPVHNSF00MM1ZSH7PXELKACHOK3KLK5CH7ZTO/KBAQXPIUEKNVDFAB11MO6C27PQUKU550TSMDL6QZ&7GT/2GZBGF\GADHLFAG8/ALRZCY6/27KZOJ/0J7INZ6USOE4F5J4B77BKZV6EQK1TYFLCIN/A2ZYYFWK1GWCA8MECIZA1BE/PFA7J61/",
@"SM3MHIQFCKE/6I0YMAI7VMI\X1JSE2A8RYX1E&975T\Q/GDGSOUIX7PFD41T\/BNKITHY\UNDOCCO4BRXC&2I4LXJRXMKQ87SXG109VU7HFI4N3L2K88\LES/8/GNHCZTIW3YN41UR8AZC591LWAV&8GT134\PG0FS2W3&0PTGOTQE58DBRBXCETMPK9XA3ELI8GMIG1YHTPYO3O8709/ECCOIJN144TPJIIIZV773QQV28\Z8A2M7HGF64E&7QA&OFVGJM6BH1ZUZNL153BGVCCCP7R8B3WAU2U5D24QS5ARTLF40EHEO7RLDT4O7/AQFZA95TXD\Y13CXVD20I/WSZ0LJ2X/PVU4WM7LI\GTDF2F0JS/0YH2C7ZAMYW4AFVDG\TL15U1BQSM9UYAJZK4N521Z7\XPPS/WZ&22HI8ET0ZPND5AWUO842OJ5Y769MZ/U3KU8KCRPZ7ECLM3GX57EC49YS/VOBHGB17X6KELS/SF8JGTLD0MT46R\N9QNTCNR0COR2/9TUPHWZBOMRKLO70J8PYSO0\&7F0HH4BWF36&PY8LMUE8J4&WA5TBDSV5VQNRHUP0FXB17JUNF6WD2DFDHOLASZIBR&LQMSMWTVYOVM\JU3M1IS0KL8Z6IOHTO&J7\DA0TAWHR4V8PCT2MU5&MBFR6SOEOF&VCELQ3ZHI8T5UN3RG8SG7HKV/\V6AYR5M4&6L4C&0MXD6IXECBHJ8&EO4VNRH5GWR0T2N/GP5TTVWH21NR4&RI/NZXC2QY47FBYG283E85QPSW4W6YD2BHEJ2GC28Q\H1ZQVVV&S0ZEZ4U7D5S84UB5/9PQV5BJR6I16GJAKYYCODSRIL&9QUG0Z6SZGFQ0ZQZ5W6A/WRXG9&R7Q\HK5E59ZVBA0X7FH/P/QZ8PKCN\/A40OXIH/G7VY3GA4AJ\WS\WUQ3C5&347&Y4OYCOZIBD7M0T7XJ5OORC5D7HRFEHD343VJPPGX/K981H2KII2/PSUV\L489UD6&DV//XI7",
@"Z4RHF/OZRG99RFOLI&LEYK0PGD8XZ5NYA7LYANPB9ER2YHO62J1\MDJODCACB3&Y6L9X72L8WJHT6/4&1C8QEOL9Y/U\MNAFE58MK4&A/6OC82UGKBO&8VUS&&&9HMVJJBOABR29C7TLAJA8PO0L\BJVLQNK5C5XKF66OTE6MS9BCJR3&ET5YKLI562XDREAB8A8QGU9J7&TEISC&XL1VA\A6XBV4U27O8&HIWN5XXW4K4DWN0YTFQRB9AB5E\F2FEEJJL6PKSD\QH2BUSHD9J2\R/LHVU0YS6YGZ7NC6IJZMSX1L&LZ4B69PG4L&Y725STXVWPZFFK0&CY\MX9VJB7RA23TCBCIOT76&AF2XYTY4F9MV5\O1LT3YCW658WDDCMTI5&MRH\XUI076R/KD0TCAEI/QM91CQV16QE26Z/UM8IPO2&O\MAPVJSDWB8FLKVE0\AQMHQR3E85V1MV32PFGX/AG534JCND1Q1WB38WYWTOI4TG52U51V4QTLBY034EEA3TA76UWEV5PMW&TVVPGYKC31K8Z75XQZOGBJTBIM/TZMD&JFIP/S202LW/72L/O2/P/JBXTFQ\FKB/50X0PB18ROTHO\GTB&E/O0C&DY85C3VSKZFGEXVNAC\V26IV/FFEWEXXW4F9606B/26&PQQ39M2TKKPN7G6PMGDAWTB4IEIK219T2\UU1PHJPENMO4C07Q13Z5Q8PZV5DR3VN9Y8YM0/&6YRF1QRBVQMAF79UYFC6OF/N5&SGGBU2345HJE3VBRUHB1OAHYDY10EN2/L8U8WKOB2V7R62XX99K4QR5ANEZGET7P\L68AF7J6A&5G25NAE4IC\U6DUUSYI/I1RTU92W3BA/PR&7XMLFA2ZN&4&4TYPYYD4E1JKRLUAGBBEPDZ9GMC/TBET2//DFYPLM08GOB76S1SM[=12=]W161JMWGKCW3UTOR8VZ242HTVESIR5V5UCOIJQOD2GP5WYTNSB5/ZJ96TMFE6N2ST4ISFFHRG",
@"W&YMO//YE3P&YFLGU2/LJJPR/M5PAIM7N3DJLTEPIT2WMS8Z/MXQJG/MWGPCFUX8RVY8BB8AXVC3U6ESQFS1Y8XH63ZEEBK186F46AX9RW51EG53B9Y&B9KV/RBKO38WKO700NYQVWKBC8DZ/9CHPKZ&VW7P\MU01JQ2MFC1KIRSYJSBNPNS10GA18EETJSIBWN6SNN56O9H6HNME5BW&C&ADQBQA\HB3IQC9ZWACUZM3\GUV5A0I9I&XM2BM957G8RX3LQRJATSQZJFJT8I\T57&RRW9U0F14F8TW4JOVRHP3V/DX46AX9ZDXXL67V1MN3ZTOY01Y6PCXRJ8TSM37FE8T49\SQUA28B&9R2&EEP4TXSFNQNOI\RIZ4AW11JILPM2PK\C3NY33NO9L3XCCG44Q6NFQFKP7GSEK33DRKX8M1SMPEK\DHFFXVMW/6YXDJ9W8KYVATX5V9R2OA3M8ML0AMT2RGGYYA5D48RFS2/WWNX0DXI9DM23/JVV39E6N&GUEO/SWX6GO2D015Z7\KVMLBGVM8OWYDJXGCW1Z2NSSVPIG86/JJ7CR7JDIOG0JKUKSSTZJ/HJ/C62Y\PQBQMOIHGM6STLVZIIBE20OH0MCYFOATRJ&2Y5/GBKLH54Q90L7X1UI1C73ALXC5LNBJL6AQL7CSOHP98G/6UQ5/BK04C/7RIT8S3HX7KQM6R3M7R6EFZIL8UDIBGIONAYJ8L/G1VDWDD\SK/5NI514AIA/Z\W1CCURVUZQXWYH4WY\DN8FUL7I0L&U3&OUBEE03TJ5WPEIOAINAASNG9RV\L3JUF0YHEGZR\HXECWFHZ70DZT2UANE0W1S2&LQ2SAK6V8C57JENLNMQDG8Y/EH3CJ27E3FQ1YX6U3R/Z3J3PIOBZ6Q54O5T4XA5DAFNI8Z06JYEHARQULWZ80ILNNYM6EC/2Y6ZY8VTW0IPHLY49P\SAO/Q47A8JM72H1PVG55Z3CDHS5DB17PQFW9O0Q7380KJ6TIS9CYEXM2/",
@"K3\&3\GP/RWY4A72\B3D57N\WXFZJL666&D/S7&9T8LP9X18H8GVVZFQP&PF6TGZX345//KDB7W/V\B&9KSNFKKG60VTS6DA2Z4G58\JYCT1DH8Q/QJWB5UMTX\KP4YI4VI8H8GBLI2C4WDY4EVBXT&9FR0H9176RL/U&&JCKHK5CRV9UMSKIWXKWL32I\EXN8YSYVZ57T4PJG61930WJXY71ZJU6LDZSH6CL&0ZP25HAPRB5RLUO2K44\W\VNZSMW1Z87S08WI9BTZVJH1PAVL29CKMP2DBCN7R15G\&XY5UN2LMB1OYKR3KWGKGSG61YI6QA3QQ9THWM&&OA2Q58DG2CNP6MSMOUAZEHKO87B644GTWG9F32B6VBEOZOWDRG6BLN8H2OUJO5ZQNWYSHDCD91UK\PY\EHJL1POID&L0FS5V9ZEWHWDJ5D6ZA0873A4ZWO1/HQOI5P/R8\NMKB3VD&SYW2HPEQ9E0F&V/GO4H8RQFP3CNWW1KIVW8DOSI&EOS533&4OEZ&NIVCSG\FCV7I7SXPZ758VI3C/MYACVHSBK7MB5YHUD9WUK\LGWFUL3RFSSFFV/CUNOGWXKN6IXORLGV0ON7TQZGK627W0SZWAPJFEO19ILL1P&6L9S3HDWE0I827P4G3Q9/QVAZ\KEOR878WZI1RTRLV9IY6TRFV3YV/NT92VEM&M3A8&6E\BTK&YPTNP5R5&61KM/IFLOFLJGI270MHTJNVM/AWN30TASB2VBX&ZCY97MGNEZS5MR93YLF2YE1YL3ESG5CNUQYR1&40S048AHFX65PM7/RTHIBPIYSG1FK96SCZTRK/M5YDXUZOP3TX\FJS\PR6HYG79J4N236P0TGOX/41&E3\Z0/0JW1DAQ21Z3GO3MYZ/E/S&77AX37D8IIJLDDGB2PJ3S273Q\ZSDBV3S1P10SJWZ5RU/CZISXH201TEAKH5HY4G0T6O1ROJFZEZLM5NLRAS65C4HK1QLRPBAK6RJKTBJ",
@"/WAW760R7T2YMM7QCHR3\0KDZBTOEB\J9ICHNRA\R\ZQ1/\BGDBKL&92TH5HD2S4ZDQYN86A2&U2XZ\DUN//91/9MM0FY681S84YTM0LJBVMSGE6J1Z25U7/FUMBH0O9E5J28NWHZZ18FYRFH69/GF9\B6S&AZDVZYIZ/P/8FSDF5&4UCG6N4R3K1C7WG&VGIUQ5I59A50C3FBB/96624H8J2Z18BVLDXZ3KEK\BR3ZC9GFZB9ZNG5PAYGCVDB&JP\FTL36Z85LAV6NVUC6E8\/5K2Z/HQ/Q3PZ/AZNLDAROUOS46TBBH8ORBNJWE9RR77JFGPU81VA7TVL8J7E0P9J7BI90P3GHWAUZEMYR&FMZ7T/SCNMJ53C/YPE\S7S\O6LTBY3/JZ1JXX&UKQYCQ/O6/WA2I0\E0OKBIRRQXPAFB6NBPX0CJQURRSWRXA2V1XWJM\L6&HRA9J4DI&NXA88K66W38&6W0SQRKE2QL6DB\TVI0SJY0EV51MPTPU\&O8NR6N6EK9MG56LMKNDQ3I8W9X2/1JB38D0CGEPNYEN34PA7ACIBRVIF&3UIX8PB8VL1GIGGY7E4TX8/YA&LN7UDQWG221M8IEL149BC13XL7\AX2A9K/7YF3W5AC9UJWPMGF2&9XWKJIRVVA4\M\GRDZGRK0103XPYLV6BA&ZNWO9LAJAL\ILXJ8DSWUZ98XSXC/KR//L&M57127QB0P1UM5OQSNSTN3S&9MJD&VNB/LLQAO31DYJS8/KJW7&XR4YWN85QYNCECZXAT\PDX3P2T&D\B&UEW2WF02CFWMD3WEQJNK2XR8A1P9CO57PY6/UNDSN48KUK0ZGPW6X4J901282301M2/R9YWCG79HO2A33Z4\JYO/K6XH2XEG/5NI2U5T037LHSN&7&&A/OSMD&O3R\FM6VKVP4AJ7LKT3C24SYM3XEJWMBF3FCB2XVSYI4WCGYD&VAJWK6YP12L1JOZKD5JV8IXEW1BJ47/XSMSFTV4ID",
@"I63MUUIQ1ZOOVEMPFAW4OY641I98T4VABRZP74CG66DIWI9IF2OVHQ1X&\YLYM9/DNNDR/VN\Q\VUYHSL133P&5Y3CP8G3VT9FEJ864HHBX4RGCO4G&9WGUEU1NOVZGH7RYOT\WS/VVOPBGW&AE&3Y/3YA1GSPZV7P9AU085XT&BXG2TV3PUUHQJU83SKPAU8AU&EGCMFMPJY8GSLHY1AFA0&0SY/PVHTSGWY2PP1COI4GYZ2KHC3MU3A7AQ1QP33I3G2W6V5J&/3485B59ZHTQH/QW42[=12=]L0YRWQS9FRZJUMX&I\HO8T3WK4WIMAB56V1JFMMPW94HUJ97NQN6UW54/BH46JXFP7Q&XN68Y55VBB8288ZIKJ2/MDFVVMLY5Z59J&XRI246BPAF8EO1TGXGJ0B23DKS0E2PJ\S8LHAVS99/DAZR\XFYCY0WERMG/ZX9/ZTQLGB1N4DY3Q5TD\DMXK89QT8DF2\KSD24SG6SA9N57IY5D\VLLZ3W&5K\VX56FZ1BB9EYL0/DBHUHRNYA2H4CB9GBHCO2ABCL&X3H69&Y10U5KDTI&4DZAF2DRIMIC&FIH6WRH5IGNNOO4DWF3I\ERNXYR3S3MTYUZB8ZYUXL21LZ4OMNZGS6BA47J\&QMR772612H9UIYZO3C/6DRFEFB4SZJBQZUG\K7Q//ZWF2ZJHPYB4LE9&GN15/NCSFT80S0E9Y&9R7AOT4WDBIKEUYG5/FYAWXD&J3V21UFGLISFG&HBOKAK8ONCL8H3A&M63AF2I6OTDD5LFAY//XYMW6D7QTR6NOGL8YPF7S5U8UH4WB9KKJ6QOAK9/KM2PVG1/TQTYSDS4EQCZLLOWGWDV2/7OSIWFCFNNS7CYQY4GNYJXIJY&\GI&DFHWVFGJUM2&C1GRJ2GU4/IE1KGIXWH99OKNZTCKSVYA9KUTDG3IA1IF/D7L\/Z/F6D1R65308CILHIQ20FQ6HFEPVY3MU918CH5BJOAUFY&638QWL5JEH/8WMR",
@"JE9WUMXMFJ9Y9B5Q3WFLZ0HHA20W0FLJ15E8YWE0JR2GZZ9HL3HMQB4V/2V5ZAYA/09D9/5HSSCI\AVN5SL//&60AVALAI51IKO/A6/&WX9GHAG21CJDNGGR6PJ4WXAI9&/F80Q\C15L7SEZKET19QB60SFHOFXX&E5\V0P9HN8XOKWTRDLLT\ESPUJW/EHL8ZQUSG/BTT6S48494YFU1ZM3AMVBQ6&DFW127BBKFJ4&FY0U3M5L[=12=]WIM0UFY9Y0U3MHGBB2W8OS8MXOYAKDA0ESATPHU8ZIYESPMTO2LC1DLENACGTXZUZ6Y7H0Z7I1JG737ICFZV5\BG9FPFNOBWERY3RL0CR7A7FKWF6EO\E118W1LUJ17MHX2MISX7\SOE/HAYVJMJACRP33H3AG62&1ZVUK/OTU&YNX/P0Z\APXMFFNVRL665ZYEJVSEKM/3SD5CG64DNH5MPPUQG2SDZ0G&1S07IU11R76BMKPYT3TY6M27BC/V67D596O0G/85TE7UVSD9M7W9GVGP356GWF7X4AET91SV80F1RHLV\BI&KGYOZ&9NE1INKK3VNXAYPBATPS/WTKHV98MXO3694ERGR4RGQ3HOBXXJGF&HBN66U0RO/GGX3D6KW6BXA4F3D6TLLDQJ4Z8RKXZ4NCIKWXY/4MZMEOGKHD31GFD72/6DIO&\HKK\V7GTIVU&QEEPTXJH7\XH&OVZ3U2PM0E7EI1M/KTYYEQX5QXXE5EJZC\GMT206EZ3&KLL99KWR&W8\6M/EKTW8HCJUAQU54UR0YVFM1IVU40SDIO0P316GHECJBO96BZHCQLMKHXQC/BDUWFMZ3FCC1LTTT9KMM1SFTQZ/BPIFK3IFAVZ9CJD9WENF464KND3JV\BFSOYN9/5/CNT/JNKCYWVOCUFHX/4G&&XCUUQ0X2AZMPCRM6B&61Y&PZC\JQ2\FY\D2RQ2/XS8V8B0R18495NLNYZ7RSRGABU1R&28PMCJJ3QUXPUUV\CMK02D",
@"4VKRFL8UNNIR\&OW3DCXIFJC/9YB\IQ4JYD6CXD/78GKGCWWXTWGXE8ZMIUJZ6VF9RIN8UUFAE2M\87NBRRZKGE2RU7D7LBNAO27I0C&QGTOW0NMZ8XPETYLDXR&0CF61&/XGAEOOSIDZ2G3HUR&0YJU2Q3YJCLOB00X33GY4JBYLVYNR05FXGFD3Q72JSELG6C&CWAQO5HQXXJH5QHVJG38UX6M9QPLF2RRSZL70P45TFHZ/6LVBADHRS20U/Q8L7G42FEM87OE1FKTWAW0QNLI5FA87OCRY&P/51[=12=]HYEKYOAVJR781G2RQ9MH8\UW7OS22N17B9T5IBWRERYQUH3SJ\T8P45IEVQK9L692&64Z/ION7CQNEBZXAT465SKEK00YLV6Y20VNL3EVU1O8&T3085CC9TW0PJU3BMI5YRTMZHHA1K/V2P1G8YZBWZ3B4KQCIOTITWKUAQA1XBNZWA\&UN8Q0HJRVO4E5N42CFFGGRX\QULES3MQU8SDVLNL6V8Y9TJ&76OHR51310WCOX981H356MXV&B/LLJZ4TWG0BK6VYYKXDWV9MEFYH&ABW86Z6QOMMAV4QJ6QOIHICASPTB\GDAWUVEEGRG1HJ/KCB3SDL2K&54\WPQG5SHJLQAILE0\ITA\F2QN3V88O3X23GU3AA92C0\YAUG\X3CS5656&DQJWL7V6LSFX/\HWK9R44NIP9LY1E//N14/X0F36Q51CAO0579U9OCH3H60AJ61OU58GAX8EGYN&YGPUY57IPB&YWHP7S2WWDNVISU4JAP221IEARFPQ&T&T6KW6HBZRB48LYGCEBYHALJ/NCOQNNGXWOBPI/\B&3L0/N6PKDLPOM\HWMJ36YMD8GL/W46GDWHK&W&AI&FJB4JKP7580HIOQI43B96SJEM4E1I&MJU6SCBE/BV2&/T8O6644J&MF0A/SRF0Y5VR0O9OGZ6&OETLYQQL8RIDKI15CEZS97DGOBH&/SYEP&\BG1MBB74HX",
@"SHS0ELBANCTAN/WJQNQ6D0KKZYN4YQCD9V962M6GWEC9RB6425YTOOU4/IAS/KO9AQD4A3TDUJJ\YN5Y4WB64W1VAF9ULNIL2F9A/B3&LV\EEVFWPP1NIUFR2U387GB/ITR4026BUJXWRS&MF8Z7DIASLPL7FN25DGMZFX2\UGA86FDL8U69UG7AT\TKRHU5TKFNGUG0N9HFYGM&&XU6K9LLFGERUVK5NBZ5FVOL376ONM\R&M00UW&6I&Q2F4YP4XUT6QJJDQDNT464SCW\E0TD6MNO7A1CNQX25SYVDRXESZNQGZKDI0KEDR0UD7OC1B&CHD\&RA80COXH&9II3Y6ZFSZO5ERICVPRZKJC0KYH4WB16SVHZGLDHN/1RXHNV0YU&GU10FVT&Z7VQ/UMVKV8JMJMNUYCDLZE\U20/6UTY5EVSOKTC74LE2K09INFUSQ1&2X9I7O22CKRH16&KEAITNAIKC31SP\FOQV23OLHSCVBR6SIOO8QSHHZ2OYGDZJNDEC4FEI8552R4QWVNDTV0HI9AP2FE55I\N40CKF&XZR273XIWVMF6VQ8VJE6G01/ZWAQZ9SC\U/B2TBK4UWWSZOQ98F6FM69\UDK2GV0CJHMXPGCH7CYEFR&IXU43Z/Y0BDHP3UX&9TIRB5T2CYLKI55DDCFZ49PMVYWM\ZRNRZIYIUG4AB1BYOSIKEL0P\IAE88PJH3PGVXH7V8NY2IO1HGNC7O3/SQIUMZ4V6KL70V9YCJ25BNS52H1J8E9BQANFOZU9E54R9TBYJ2&XYF\Q4F/UZ1OJRZI4JP250JVA8IGD&GFMPREHGP&XGCDZCOPSSW85LZX/UWVSWB7&VAXKUM6CDS/IF50U1VRXGRXJRLRFB0TB5D6P7HBV&IWE&LQGGA4BXJ5DPO6I80BP&8QC\LZTT8XTJF8K\B8SQVK2&TN60LHGFE8NH8OKU2Y7I9E1MX2&TUR74ILGF0IM40NFJVCDZY/19QUDPZTCWH0Y",
@"ZBV&XHE6UMDUV\S4VYN8W3/O1H4THF3WA2TI&DSRTDGXM&UQH1U/74B8DHKPQXZOVTT6SJ5RF8PSWNB1ZNMTY62J0XE55CB8R5B6T1//9C4&PWM3FW3DLF224KF8F&ZC7TA4LII/QPXWB37ELOZJM/XLCMCIVC49Q1E8VUS9N508VG0APBX3NP39922\G&OOX1GNY\V3929UK139ZB6URAVA\I&65T3NQMK7&NORT67XTJYHMEG79WFFPP&2/P&VD\Q89MZPAXG\U2X47&HYGVP027/&R38SY/FZ3D/AR46LQGY04H8\INOUW2FBO0/K11NWW\B3CHHP1DKWIKHK8/KKWXCA/8Y37WX26CD6GE9AF&6SSW6DT0O4RCAA6HVQUFTU3FHOD4BJEW4XVNBVKGH5L3CE/GK1S2R1&/609FWX3H/QHLSSFAGO/0J&DCQ/TM3PFDYXTNYEXXCD5Z/Y05WSWD3L17X61ZDQRVLE08OB4NXFGRF4J13L6CMM8Z25P/TZZKO53DUMQ0V0G1/PP0F1I4N&LCWY66\T8DM6Q7&IL28ZN&WDSUE\UWFAX6U0U9SX2C5COD\U09QT91ZMTSGL2A\M\MIXNM0PJL9KHT2OVWKXFYE9HHHB3H72ESEB8OHOIAJX4OF&242F2OGMHMQFEZZCRHG1O0THP9OFPUE5CHL\R1&2L56W\BJWOGGWIRYCLV35&B/0IXD/N0Y2HQPW6/JOZ43IOUXXWJ08\H3K7GON\MJ0VQO5BBINMOGHK1M0ASND&33AZE10W8QNVD0/F4WVAMVXBVAF60NS\F050OF9MV4RZHBPUI95C0HG&EEV78V/OPP7K4ZZISVEYH86EQFEVFDAYTOA53099BRK4GF3VKXWFCV4ILRQ2QOIMOJ3PY6R4YIW3YB/LOVLVT8V\W5TLKGSZJ\Q9ON/QF5T6\BXKUEO7CZ6S1566NGUS2/T0XA9BY8Q1P1&VIJ4F5XWWE/IWUDD&KADBU9ZUIMJHJFD&5LYD",
@"PO0EN/V04MTU4RQOX\ALWK9SOPN&7J4JS&W8N&0XN&2961P412O6KMUFRH3\WV6VUKC57UAYKP/WUAZ0&VLE7\FRRRGI2A5GGOWYX/H12V7P/XQVD&AK10WL/NPD6PVOFPNZDBOYDQFPE3U7AYF3&UST5L1JUD7MASJVJ4SBXPGLVGHH6VDIK5PX/774NEE&V5PYT\XIFEFXOH\YDUQ\AZCHDYXP901SKG223W07/7CFZ4J29J151F&82HU8NIMSQZMHRI7U7VAGW/VMO8T0&84FH6&VB5T2UW2ARCK0OG\FE5M5ZHTS2YTU7H&XILTCCLZ&HV8MX5M59ZAPUH96LB&8DHFJCZRC09C6GMYEMG7/M0YIHXDBPZ3AL39APYK/NKF&WHIHW4TFGCWPW/CSWQZAGCUQQX1199WCUYY&O8SYFX7IHTRSV4O/XF6UZ54\C5IKTT8/LCD0/A7VHLJ/GJGEVZRP5ENVEUVNOX20XTHS10&WKKMNW646YE26BTEH2UWQSUGXWVMZC1Q708EV4&&K222K88ZEP&2GEWE3D24BTE3/07GGOWQ3VL0259209IKC\J2D3NSCH/4X&4WA2S25W\X68P\G&EEL71\RECPAEOVXUC2AM2\QSRT&Y9IOPLCD6S3L5F8ZD11IPAL5Z/7KG06PI&5I7BY6LS4CLRHH6LN33KWYXP1RQ4/FYOD6N05BD89/IJUH3ZR7NDY/PGXRMHPUVZQ9OO6GTLZ8OZQO8T13NC4V3FRGCN29SPPW6X5O6KOCQ3W22JV5SYGS78GJ/0DFW3P\K6UL1M/C02E&W1R649Q7I92/QWQGGJS0OXS91KEF0D4E3GZJIKNZMU2NEX7E948RJRY\IUEU4KGEEYGK9H/996N67E4EPAJ8HN7MU0B0F58BNXJTQXH17&VQD5DD3AE4BL93372IGJ4D\LSJ8K055UAI4QJ2W//F1DAC0S2W8\VYISS5N7ISMM&TK1\NXAZILZO7LPWPVE/6&PAM/RO22R5PEU5&TP\",
@"7MNNWDYT/K6/HOFU80ZPGY9T66&33XW8FGCUZBRJM/QR8UXA&A9M7A4JQ6T2D73N1/5BMY76JQCJHRXMJ&430KBFO6D5V1FRGD3V0NFDCR/UB&JHTDD&ZR900TUBLUKXCE0ZX0MQYWHWH64EWOIBOHQLBC8H6D5VGMR/LWW64ZODJMS62QS9LIJ80PXV4FXU4YQ8P65&4PK16NB1WCRPY8J/CWK9&BBZC6LY9WQ8XSF9\VBMN8H98OS55W9A2NXYABQ4AYW4F3N&UU/WDDL&79QJR4YL1SQVN9BL9D/EDP4FBTKLZN9YCY3EYHNJALDZM4YYTZZAGH8SEKH\TMZNW4T2F9Z131E4LF5K8Z4A09S82L&NAP30Z3DUK8TW&\JRDDG&S9D6VZ00MY&6/L1O\QFVBK&&GIA2ZA5YFA8DL9FACQIZ8ZZ1J8TZ\X/H/D0NY/AM5O0/PYCBLFSYCMDUVLT3UG0VC1GIJ4OFP86ULX6RN5EMEXAG4NRJ5Z0F81S75T3NIGSWV6A8/C57Q2WVHDAB0FDH656WF&Y6B3D\EQX/MWM2762FF9Z2T2ZCCL22AQ2\Q&5ZZYR4SD1E6ONAD1RJM9NMDA8508/86OL7ACTUR7KPAVJ0YL&TYUZTVY2ZDXG5LSDSABI94SY/LV4H6\JY9M33ITT74540JIJ4XT1XDC2G81IA6U5ENU9&2MKTUNF&0DLAWNJZV6XW7TLTAJ&ZM1LKBLIIC2/3S/AF16/S71&COFR4IAM8&BZA4A\LEBW597E/SF5HMT4Y1J996R&BPC3RKAO08ZO6EGFUAULCIFWSJALUECSZBVQ7D0ZS4FMZF\TVDO8MF/6KTLHK16V5G14W3LQN76KD69NLU3Q3GGUE1FO5SP3\WTTQG/44\URLZ3RW\P5ZAHZ7X/Y8RDMTMP9EX\Z4Y1IS7VZ5V47TJTCG7NZAIMKEHB5F&3AAL\H99G3N4K41S9ZXU54R&1AF1WX52T5447HLMFJ1WMI/VVY",
@"KPIXH&VAX/CHMV/XLR&/Y1NKPVD80TDWG\MQT8Y5I6XOJ//FY1/SWXAVB/IY80NE7SBOJUEP6G24E&BRX/J\WXAV/4OV0&9VSTT49V9EXUZQ8IRC94A\QPVKSTRRFV26JGMYTKVCBEOB\X01MMZ8\ED\JLPER\C55G196VZJLATL852F6867KCIZJ\F/XGLIFQT3&ZAB5CR/QWPMFG&Z1GM1DBMF2LGS7/YC9H7IJFIMVVVKAFJHUMDMRLV&2ZNF4R0DK4E0PW/AFVSBFWB&/U6LYXY8TW4DUX5DX/8RC7/UPRFAT0U4D4AIXORZGIG547SV2ORH1X9DWM9HSYO6BA&2WXTISJL70E3U\XKEIMCT8/YLSKHV6M3382\F8I2SMCPSWOI7NKY2/S7Z\I3IB2ANN&ZJYFJ&XXH6UG1DCMHW1B6P8LH0SUQWBBEX2&JIAYENLBF4T0F2VQYLGJOM\WUDHX4SBENCC&WD/TE6GPG4O0BXQ5RTY9KRDAG0J03ONDZV7VOZFUFVP32TWGCI07RF2EA9NQXTY4RKBS38R4NE41BNLZDCYU1SYU53URM19Z9XLRSEQH39TNOBC0Y0MV8ED\ZU0ANARYHE4RB7H&YQ34&LF4076ZPN45TN5\RQ63S7FKJYZ4SN/RNL&NO8MSH4J6N\/1BJVHWAMEG8UCIBGCQMSINRWVEOW0YL9L0J427M&7HTOKKFXHPAS2NXZADIQZT7\IOKM/K1SFISKCH6DRCQ895/XFW4YY9MOMVF8A5091VNT7NW5JF&WC&BQQZHNTC6J9E/UB/DYOUGOSR35A\PT93LNT1SNYNQY1DX3PC4MCOIV50\&9PMU0NNF5WAMS2&ADUZO6&P/HCRVV3V63SRJA8\O3R/5CR6MOHRKAWG9&PNX94XBBGWAL3&IWLXOBW73IEHNLK5GLUJYVNR4876BXHJ02QUXO5XJ24NP14UOZI6ZTF5&8PDWGCWDHTZ6D/\ZOXGAURFJD6WS8ML2XV",
@"1&1AD0HKHHF1K2JHK9&5RQJ6TMSEH8I9IVJ&/OUS5KK\EPV7I1BP35EL38T3HCCM\IS2SKJ9OT&HGL1E3Y9T66GPQ/IC73L3H/&896O/SFAJ5/ERGPAWGWSECDLVCHCYIJ&IL5I/J\B169WT538S32WXS866U68LCPBW/9GOHCMHV4LFT52LLX7TZP3Q&OPQD2YR8AV9XUK0QPB0X1N2EX&SUV9VG3O508E5G6JSK504MGDKNC6KB0MT3F9NDA27FRAULJU3R7SL9IFOSZHD9D4AWYCA/9OJC6Y7GV\EVD6GHAWU&V8Q5Z/B0&/0GT6USIIDWLH90DV6KX5VBUAOB\RQ8WHGXL/BKL0&5SNDD4CHPYZSRTU34IAEALOFTW\/63WWMACH2N45E&I0KV54GIAK/XN0OWXU5FOYCDGQRMBRQH&BC18/4G4X3LY10O6G2K&&YXYHPON6GV73XLXZ0Z2ZO373SR3CT81FIAQSD0VP6/QHR8EO4GSDUNX7272/YKNL71UW8FWAEN5QN0MXNOLMPYX7PV2I\X4VXEN2NUTZWR\HVHUCVFXJ&A9JE0HNPOCTWJ5IMXK58Y2/ZQMHAZZ5AUWWIDXZNGJIPRXLPL2ONL\W1N&M32JTC0IAI&XS2PUVH5B5190/IFILKU9MN6TSG/VYGLT&LMZQO9MGX6BLL9R/21CKE88BOJJPZPP1Z9TJT6FAAGJ0R7ZZGIW59AH3D3BEZ9UHQMZPPHR9VCK/ZIWUXWIQ6X4Z13G25ANDZBJEIKKZJ73JE7GTUC0DN6VA0YB1DV1GLX\SMMMKZHN/8SZLVLSLQW1QWIXY/CW1FX/U81HI3QQGSXEH&3F5CQ228V8D21MWXZ4LUFP7DKU&FV/\DPYG/3Z27IYN6ESCD7V556Z7OL1483XNX9&MCGZ7ABRMTCA&5S9K&EGK345ZB77EYK29EG&/I154ONNMK2&P6MNS31WLNA5FHM0JMD7YS\CLMO9PQTOM8RKM9JGPX1WH9ZWC",
@"ZE&G8N97JCGO5G87YTK3COMD/SB4P7OZ562LTHQUUPD7D4WR61VQP6&L59JPMFSO0TV\QWNRC3IZKS&F8X[=12=]M\K&7QTX/BHO/1GWIXAJOENYXMAN9DU2H4C1JWE&D3TBV62WMQ/KW1MHXYOUQG17TSHFZRNYTBGYXMD3WRBSGJGTS7EXIWW9BZUCZX97DL4UU0WLUX/\FI0JM1Z4N2Q9SJWAE&VGP8SYL5CXZY46\L3\/EUN78CKEXSUS\P4027TU05J7R2AUKGBQYCAWW100NVE1I6AFTDICYA0BYH5OX\JM9&M34HDAH6HE1VZY27AH/YP&\O9LCOL54ITKOM&I845VNCVGZ2\CO/H0O4J1E835684QEST1I2DA57Z862ZNQJR6B68WCKDAAA1RLEBGIJ7Y7G7UFN8PIQPXR\PLW/Y/YDA5FHX10SEGO5\OQ2P14WXEAM22XLY9A4GBPG12MIIY&VNIT9V/LQIAGK&/85VR5G09\S&IABKO9ONGPO41OCT36O4SG37T03657RJB/N/KG6D5/5VTB6D20/CX1TBJG31FVUM/F34BFIXAK&VOIOS70DF9OZNQL0DPF\JPSXNLBCXSNCM2[=12=]B5K7SRPPWTPO2RFH7M2F8XAH5XT0WMNXRYZKELS5ADB78ZNFMFH&A64R5DB7/16JG4/D57CW79E5VFLFKONQENXX7IRBJX7MJ41D2JNSDYFD2&8049XWOPF5HMJWPBMJB4V3RIPBA8NSIU87M4JNALZ89P&3CCL8B/QFIWTVVSBZXZROKX4&J360EVLABK5LGMS/QHW06R3S5&LJ\YTRLMZLD3BZKTUK03SKGT/CBDF4AO7EKCBQ4OA70H70G9QN9S5CUBCR0QPHG7L189PIRETL3YW&ZJ9F058VW5XJ&X2N59F5JTH85\TM8RD4QUKTN&2FCMGJ7OFN//3DURZYS/CWDT1485M60MN6G&3/N\AQ5FO[=12=]AK&7ZAQ9GBVYONCCMZXW/9U02K",
@"U/Z4/E2E8UN\BM/9A\HL\Y/OTS4P2D2LEOTSKPDR8KRU2NYLZB9WTQM8&KLSMNO45B6Z6RYY73P1GQZF7T21HG51CXT&EYEV9020T\SIPL23AY2WYFX6XZXZJFXI/YUIY74T0\Y8BUM8QB0R8/O\BL\JCDROOJK34UEG6I90U24CN1IHSFNAKVHN8VQWUKT4KWE8/TYZB1RLT99O8J8I9JSIN4LK5MFJJA43WMK\U0&WE87\ZB1KOK8BD9VGIN61VHCTEF4V&/1IK9DR9MY3Y87\E3004E3H6LB96O7UKGLRWZ3G5DJ82DDZNEOORD47GUPHYVSDTSXPPS&T8087R3HOW1ASCGPQKCK5LYR1PYWXC/28O\ID&LCY3UY9V&BMDGFMIHIKIGR5GXLY&EEE/LQ\&YB3AVFQXKU85P0H26JSGI&9Q89P43GNWGRJ0BBI9CQ6XQ/P&QXF2G7VAY2V083FZCDAK1H45BVE5GMA/UQNFAXQM9JBLTVBLLGVN9EKI5M1X237M1XFSP&YRZ1OSFSLTT5U&30AQFEM085XGO2X9PW9LVD0I24DNBID9J8VBW1MK0/V7DIEP8PD/9IR0A51OB&Z0109SHVM0KYYXU6ETZ0RYEG&AR8B4A/I0K7FPLYINCQ0KX6FH0H1OUBWV19BLUV0MQ/M002IAREV1T2QY37E6J7FJLW1PX96U2N7ZTST\&09QS8C&TPVZQ6CV5DODA5PULA\F73ELOG7V/23QU28INGD8KL7PDP/GKOFR99E2KKLK&UYCN\VK/HHF/C7W92I\I1KVXLTYYG/D7593Z4CE60JCHAU7CV6VCMCLJDSBS/Y3KDKEGD9EZDFUSINX3YVDMOAV3YUWLAY8BS5E2Q1\Y18\HU6B28K6PVQ9C2NVWM5YRJT&PJ7N/WRYSCNJ4T6Q25TTB8BACGPL8KU\B6YTB/95D5QAOE3DTP8Z3A\UH6K4HF2IUOHNO590PISBZ\PM5TO7IB7EMI0EY/DIS&94IFAD3CX2",
};
[GlobalSetup]
public virtual void Setup()
{
if (!Vector.IsHardwareAccelerated)
{
throw new Exception("Vector.IsHardwareAccelerated == false! Check your build settings!");
}
}
[Benchmark]
public void HasWhiteSpacesWithSimd()
{
int count = 0;
foreach (string line in lines)
{
bool hasWhiteSpace = line.HasWhiteSpaces();
if (hasWhiteSpace) count++;
}
}
[Benchmark]
public void HasWhiteSpacesWithLoop()
{
int count = 0;
foreach (string line in lines)
{
bool hasWhiteSpace = line.HasWhiteSpacesLoop();
if (hasWhiteSpace) count++;
}
}
[Benchmark(Baseline = true)]
public void HasWhiteSpacesWithLinq()
{
int count = 0;
foreach (string line in lines)
{
bool hasWhiteSpace = line.HasWhiteSpacesLinq();
if (hasWhiteSpace) count++;
}
}
}
public static class StringExtensions
{
static Vector<byte> spaces = new Vector<byte>(Convert.ToByte(' '));
public static bool HasWhiteSpaces(this string s)
{
const int registersize = 32;
if (s == null)
{
return false;
}
int pos = 0;
byte[] bytes = ArrayPool<byte>.Shared.Rent(32);
while (pos < s.Length)
{
Encoding.UTF8.GetBytes(s, pos, registersize, bytes, 0);
Vector<byte> v = new Vector<byte>(bytes);
bool foundAnySpaces = Vector.EqualsAny(v, spaces);
pos += registersize;
if (foundAnySpaces)
{
ArrayPool<byte>.Shared.Return(bytes);
return true;
}
}
ArrayPool<byte>.Shared.Return(bytes);
return false;
}
public static bool HasWhiteSpacesLoop(this string s)
{
if (s == null)
{
return false;
}
for (int i = 0; i < s.Length; i++)
{
if (s[i] == ' ')
{
return true;
}
}
return false;
}
public static bool HasWhiteSpacesLinq(this string s)
{
if (s == null)
{
return false;
}
return s.Any(c => c == ' ');
}
}
}
使用 Vector<T>
的代价高昂的部分首先是获取初始化的 Vector<T>
- 因此最近代码使用的主要技巧是欺骗并使用 MemoryMarshal.Cast<,>()
访问现有内存,将Span<Foo>
改成Span<Vector<Foo>>
;在 string
的情况下,您可能必须使用 ushort
而不是 char
来说服它知道它在做什么(char
和 ushort
在记忆方面是一样的),所以:
var charSpan = someString.AsSpan();
var vectorized = MemoryMarshal.Cast<char, Vector<ushort>>(charSpan);
现在您可以使用 foreach(var v in vectorized)
等访问内存 非常便宜 。要记住的是,最后可能有一些无法放入向量的剩余部分,因此请确保检查这些位;那将是从偏移 vectorized.Length * Vector<ushort>.Count
开始的任何东西。
我在 .NET 4.7.2 上使用 System.Numerics.Vector 很开心。作为第一次尝试,我编写了一个基本函数来识别 ASCII 字符串中是否有空格。我实现了三个版本的功能:
- LINQ,
- 经典 for 循环和
- 矢量化版本 (SIMD)。
我惊讶地发现矢量化版本比经典的 for 循环慢得多。
BenchmarkDotNet=v0.12.1, OS=Windows 10
Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
[Host] : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
Job-AWDTWU : .NET Framework 4.8 (4.8.4180.0), X64 RyuJIT
Jit=RyuJit Platform=X64 Runtime=.NET 4.7.2
| Method | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------------------- |----------:|---------:|----------:|----------:|------:|--------:|------:|------:|------:|----------:|
| HasWhiteSpacesWithSimd | 35.99 us | 1.038 us | 2.928 us | 35.14 us | 0.17 | 0.02 | - | - | - | - |
| HasWhiteSpacesWithLoop | 17.00 us | 0.335 us | 0.586 us | 17.10 us | 0.08 | 0.00 | - | - | - | - |
| HasWhiteSpacesWithLinq | 220.59 us | 4.408 us | 10.896 us | 220.55 us | 1.00 | 0.00 | - | - | - | 966 B |
下面是我实现的矢量化版本。
public static class StringExtensions
{
static Vector<byte> spaces = new Vector<byte>(Convert.ToByte(' '));
public static bool HasWhiteSpaces(this string s)
{
const int registersize = 32;
if (s == null)
{
return false;
}
int pos = 0;
byte[] bytes = ArrayPool<byte>.Shared.Rent(32);
while (pos < s.Length)
{
Encoding.UTF8.GetBytes(s, pos, registersize, bytes, 0);
Vector<byte> v = new Vector<byte>(bytes);
bool foundAnySpaces = Vector.EqualsAny(v, spaces);
pos += registersize;
if (foundAnySpaces)
{
ArrayPool<byte>.Shared.Return(bytes);
return true;
}
}
ArrayPool<byte>.Shared.Return(bytes);
return false;
}
}
我是不是做错了什么?在这一点上,我假设经典的 for 循环版本由于 CPU 缓存而更快,但我原以为我会通过矢量版本获得适度的加速。
这是带有基准测试的完整代码。
using System;
using System.Buffers;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Security.Policy;
using System.Text;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Validators;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
BenchmarkRunner
.Run<Simd>(
DefaultConfig.Instance
.AddJob(Job.Default.WithRuntime(ClrRuntime.Net472).WithPlatform(Platform.X64).WithJit(Jit.RyuJit))
.AddValidator(ExecutionValidator.FailOnError));
}
}
[MemoryDiagnoser]
public class Simd
{
public string[] lines = new[] {
@"CVN7OINF&KN4QTV/WZE1SHG/TLXON2S985XG73RBH3BO\&9/FDL/7PQNPVV6P9AC/W0E&TK\AG&GSX14PZIJQVBSPJ3LHXZL3\ROL4\Z6N91PK8564R214YOVH222PU1PTFMTY1VPDZMDFO\RPG9W\NC6DCJ98WTG17OZUK6AFOV2IEWN4TOJXEQGDTPVSZUTFFOLAM/FN8RX4MX&S8FPHKWXQHVA8KVT7CXC2LNRVJ81Z6P39QDXTEL7W48539JCN2UJHU06\O7/W55ERH\&232T\QV1Y&5O1E0BOH8C6LNS27L&8O\&\&BL3\H&VSIRF32KL8GRQK3DEW36H/A2E1CN9FE7DO/KY77HBUXS5VV2KHZPIN4YRTNR0POG4MNBNTSK2V4ZMV/WFNC1S1Z2WL5FTQUZGR0SHUP42P0ZVFL9V3LMMZ0DZXSB0M3MBFS87ROY\L&DBAHRA9W3EHMU3X6WBNDPYOXQZPBDP0OB0XCZQAB43AH75\FKY4WXIWRZP45X7SOR5L7GUGGBMLZYG3X0J4SXD35DFPKZIQ/KZ3BUE&2SYVL9/6SZGENDA3NCS3AF8U68OO&Q2DWKB&&VS9FL9YSDC6J8P\BN\WWE1PVV7C9DUDBA45XWX2JKB26UFDA3CJLRQ86CNXR61PWIEXOR2JNMC&WAQ3BGBL5XX9\UJALPWYG739&QOXTBDE56TNG05UNKGHYHY7I2\2Q61JU4Y4Q54TTEEA87XWBK91VK44UP4DFOOA5DZ8H2/RP0EDT6M7NO1G/A1JA6KAB0OF2DI4H2PLNRM8G0L1C923ZID4PQ8OS9Q1M&NPXV0Y&P5S15CMUV\F\XSUARO47B6QAXVHM8EUIE4KPXDWNV6/\L21T6PGG84\WOSDJ8AZRQ976HFPN5RLH8S1870TT/ONN51BF&NRVHSUP87L0A5OQS3083IPITGTCVTBTEKNRA2AQ\M&AO5SE&97CAFO4\ICB&R7O65W3S9Q23K/RIO700OCYZ",
@"&S&8WT40&QTSYHWJ2ZDTFL3H9VWOONXOI27MX78PYB46R&XHKR/2&FU014&A/PMY6EK8NKY8307DU/29/OE9Q8PCIGX578RI2G&N227A5C\LLQG4CDCVLPIH0GZ5B8IYOO/OGIUDEO9D34&63459/M/BYVB0N&BDC0C56097BIL7BXQ9G6CJCM1BQ92YH63EN6BD1H&C7AD&AEEUT/4A2\BP9\L0ISHUHWNI&7AOES&AM91UCMJHV6LE05CEWLZJ6W5R39UZ9P8K&ACAJ3Y8J&\NLIVG495652G2EK3F4WKG/AFZ2C7503A6YRFVON8AXCSK6M8\ASEZ25QLD8R1B&GB1MEZFH3Q0KW8U85PH95HZOE6B6ST9H&X9QVTIJ6511&SIU3ICBUFH\PNIKXM2KTTK\&EMMG/C&S\OZXUCKQ706Q/AIL/YUCRHTHKVZ837WCHTR\V0DJS7Z6RVCEDAJMV9B38SN\QO0&D4IRVJ3KUKXXV022TU52YKTKR0DCNE5DHZ2ZMYV6KKLRII2YS8W/O6K\&7G0/PRUP8/DP7&\SZSI\AS8N1Y/UJK9PNY00XBO54BMKZIX9XR1NB&&PKMI4U&GYA1BJML8YEQG\FY0TAA/5WWNOZKPK6XK481J\GOXLWDJY5AKZZ23UCNBRN0XB8X5TFPDQO2MZQYISM1VY&2YD732UZ4XT4VQ\L2TQ/7L9PDDRFVEZF\BF&1ZO0V3WF677IKHXIE0FR113ZKPE0\N5TK\WDF3OE14WJIJ8NURAK91LA81PGZ9GSCN/LYTCNMB39EUQBU3FUMVXW0WIQOIR4XDH8LW2BO0\O8OKOZ84ZGU3OXBKY&DW\MBNV2/ADFZW1XM16GAWWA//0E/&13208MAB6B1Y180UT/C3LNRS&TA/OE0R5\LNQPXK75RO70MQQ2BG0OMK1OMC02OJ63WNEUJ0GBSYAXZMX[=12=]/PZK/AFKMCUWERIVDD&M9SO&Y80JD2&S1CQ6GTZM\J/XYROH5CVIYZ",
@"4RBZZBM9GXDC7BBOOXRZOZV4OGUTQBH36CLU6X&BDMUVWMGR0/4\LF8KKSU6SFPMI43CV736ZMWJJ6WHN&OJ&84GCVJODGW/9IM4VD85G/M\VZAR8MST3GMNAX&AXP3S3YMBT4ZJDVDBV6XQU5S30CH38\E8I3G6I/N&/E0JPIDK4G&WS5/&50RVGU&0FHNM82XZCV7ODR0&0XHX\VPQ6GAVT56QE&EH73PCWMT//V9OAR8VNO1W4/S11CGK2RKDMSE9HEBYBSSLKZUB/KC2KUQ/L1NTGJITL6BUN\NJNDUMSHRBUENRPV55CHXT3US5K&AQYA1OHADSEKM\B93E3AJSGN7S5Y2BSHAQUQOUVGY4TJRWQ9T7JQPUUXCOWWKC&/J9RYUIVWPRUR7YBJH5UY/WBA83SHWBU92W&VE4OLMZA/AD3RMNOSUO&Z8Q243OAN/X2KYSEPQJLKWDA5&A7J0BPNWM00CXU\Z0APNS57I\BKC2D4Q/42T408IO1M5QN61NX9CYRTIAA2AFL7I8KF65R8&EG&4TB5XIV1EH15SKTT3DC7D/GI&9929\RS22&HE5WX2AGRZWL\EBJC9/PEZPIZ4PL3N&V4TW6DUSED31VQX/X71PW4M7V2W/5M2QE0BTRVHGVQ5MN/65C64QC\Q3SZAETW05NNX8PDTCZU6F\AUY848\VLNFKKB5UD0A\AN\P\N13UFK4REPJ111JC&RXEB0UW77P\CTK/O9Y6U5AASX0F6\JB39B8NL9ZHG0K76PYELN5DQUGQXZRAO29XNHFSPWD&\ZNF3FZIBBUYR\NO7R3ZSZ5R4ZUZJG12J5F4GB0SAI\MIKGP74X/6RTM69OEY&&8M5OZ6WI64LYK0SITTE4RV495L5/JZV7AJC&P9TWLV4FV5JYO07YTHUMV8WNAY\GIQYBXS6W&VT94ZO&CHVW5/O513RTNGVZXX9EGIA87KY/1YU9UWL5CPOKC6M7BMJ6&7LH2J56H01UMQEDIV&37",
@"3WIJYBN9F7VB5/6NNHK4SYP06\Y2JZSNT\JKC\DIS/B5GTTTK38O1&PEHVP0PXZTOHU60WKPDCLUWWTNSFSS4EYUWECUWQ57KVQ\Z50STKZ07VXBBHKFG2KWAKWT250KRKBGVP5M4&K6&71WSSUIU1D5GP/PJH30XOIXTRTZO\OHRQWGV&BJLR22GI&FRQCXJXJXYECA&86VN9O2547JFTOFYSQKRNH/6G\UQ9AKPYGPK7KNZW5R3IE\F05WZ08ZW&UV6JQMFI&TSDGPHAVPDMGXBAP2ERY22U5LN1TPFSLUJXTCUPOYFSWJ59T670I1XJ4\K8CTTFJXAYORTMI2C&XJ/VSRH0URKX/&6V4ZN8F&J&JGVCMUSSYXZUA1PYM5X4NQ1OX/VWPH6XA\MM8ENA&5\MMMVCJ1WNPRZ5SGSO&9CR4CTCOD2HRX5VROBLPTN0YSHWMU72Z\AD2UVK5S0F&O95YEODEG&TWP6L8/37J&VSW25954S/5H1JWP/HF3XS&UUM1KO8169&6QI9LRKN1B0O0W1S&V1TPCSCHTIVPWI&K1PGGA91SK4/6FZEV88GEQX4/G15I2/E61D&GVM\YAAFLUIC7D&U0C87EYI&MES3NZEFBZ/AW/UDPRSQ\Z\E2QQ46J7VNMZUVJ5YQDAHG&/3U4RZF5BZGNB/JMM55P0JKAVGZ7&8Z4SZJB4HPVLANHI7OD4HO3L0SUJLAL5GAPOKRWCKBXAF\KZN/4S8ERPIR4G24SHD2E&/Q5ATG32G2I78OI5/CWAG60PNTWQ9P7K1VAO07XKYSKCE&K5CQ\YD2P0AXN648/GNN6FCRLO1WYRTXRRZX46299YKHX0LZTHB0U3FF3YFX/UE\HQF9HHDDRRRH777XCCCRP5C1LT6G0F\OUMAHVPSMD/JCM\K83VU8S0VONRX0N/PLTC0V7ZCZX3NSV&OMJ\PFYD964Y6D44&FU\WKK2ADS7K1MC5NCKROUK0PF63J64H\XPECT/L035I",
@"U15TATNXYKKGEQKT&S/EEI/\I/RJW9X/MCQN\ORHW0NIAYUGAG4MKPWXVCKQGO0NWGE9N/VXB3UR81\XPKIQFKZ/T648DBAIA&Z6UY5CXGLU7F26E0A8FJIMTGQUFZT&2MR8CED4SG6&\FCNEQBFC33MMNIK9/ZM5U163&XJP&QJNOECQH8D\WK0F243VHJ9MZMVZKI5552CNU&\JG72CVOIKA1AH70H3T91BWPF\CLF7HNX36UPNT63LEKZWHX\EVM6XL9Z313&KIODZDKONL7J0GQ/L3V4SMAL8UAS97YY26TC2G&T/IY60CFR8&O&F&U/ICIFD4STZIU60NHE4C6J1GY5OVW/SZS3MV70QF3FHRVM4U5JIDGLIBRP4UHVA&33UETTG/Z0SW&GKB4CEJQOWAM6JVC9/IEH145ZBLCKRT5ZCKF22FQ3WOHT50KX832JR4STJEB6GF/DH03\QMG55OYMWL7NASP13WHK5YTXEWXQQDLE9LHVW/RDFF9/K0513JMYTTG46V1J3I8TA2R2K6E6EDFZ2VNQ38ZH3ZYQFP2BIIN9JQ/VJDQ9FTUPNTBLHKS8W12NDBX7ECX93JQMX5H0R3CKFJCYOQ6/2RNU0XRITV5C8XZED21PD4Q6ZRI7\T0J0GL88ZAN&H9/&PUW\VZ2Q7/BU8JOXJUCE6IQOIHD0CEXU8ZC0K&Q7/55JJO&PY22Z76GHEI2NVBN3NUZJG1MJEHHAPHE7I0CNO/0CS7WCKCL8RC9223J/QSVZZF59D8F8&AOP7W3MEJ&B8LWNLOERRF98PAQMCZ&O/Q9R0T8F&95GTU4NWRY230R7DT&6GQJSKXESOEZ4T&RUM3O8IC3XAJYJ\CNGTB\W0N88QM&R57J4J/UNEEXE0ZRA&7UM4SKRA87TS9DL5GA6AAUACOR78B888V4Z0MW54NDVSYZ0BP6K&G7T54Q8&GA6C&X9FQXSXICZ/\UR235SHY821L79905XNKTTA3VY4N04DHV6J&GJNU",
@"YRD7I6V1W9QRM0SAQ\HH06/EYT3AZ9UVK6YBQGV2CD44NZ88OIVHBG64U&J1DUBZP7GTBRXKQSEXCF3&Y7ZQOMUE&6TQ/6ZUBEPSSP6/YL4VBJ2PIJDI8YLCNCTI/GMX6XVLTJB25CU\C3EEI03QZQ5MFP8Y&R\H2R04Z937HG5JUOA2D5\Z7P\FFPFDNP2ODNIYDNSL98JSXW54PFUGTMNMTUYJ4ZT4QRGGFOZ3NZ3\GSVWXO1I8V84A9FW1JUJPRCGQYYBT466WOFB&CYQ\L87VPGJJDBEETV1POG&2Z1E2BIY3EXZXEKDWHXBSP4Q221C6RYX9Y0LW4EUHUTESPTAIRFH3FUN8LOAMF5LT&3\Q&U4CD6/9Z/NI17OLQ64EMQKPEHB1HYTZUXJ/NF0LWRIOB5YLRACGEVJOJ1AR11DXQ/LGTV7I9OMV3KGWM00S11&G4TN2H/NEU0AC4&SLJMMAZNB\VREBAY92\EPAIEA&BIBDKE5NHOIOO\URROH25MD93KDZXSDFMN&RLQZ36ZPVOAX\V6/LG2EFM&AF31KDCB&DFT03DBSRTH9DBY/KIAGKMGY1PTAEOMTMAU5CGGIEJ0YEC/EE4A8B723\OWBNCH1WCT67DC5CAYVTYSP9MNRSSL37GI4YD8XRQT8XL/96I42FQOM9HFB12JD33KH&EADDFW4XPRYJ1WYQ588Q1HPE7MJBVB5XEMLGMQUYKE&PHEV8AO3BJEP93S9LGQCI8\TDT1WARIYWH&/24NAHL4N&/PQ7TIS7C4TIYROL52WAT513UGU5P8/EXTFEK2UI33UQT2EMPVHNSF00MM1ZSH7PXELKACHOK3KLK5CH7ZTO/KBAQXPIUEKNVDFAB11MO6C27PQUKU550TSMDL6QZ&7GT/2GZBGF\GADHLFAG8/ALRZCY6/27KZOJ/0J7INZ6USOE4F5J4B77BKZV6EQK1TYFLCIN/A2ZYYFWK1GWCA8MECIZA1BE/PFA7J61/",
@"SM3MHIQFCKE/6I0YMAI7VMI\X1JSE2A8RYX1E&975T\Q/GDGSOUIX7PFD41T\/BNKITHY\UNDOCCO4BRXC&2I4LXJRXMKQ87SXG109VU7HFI4N3L2K88\LES/8/GNHCZTIW3YN41UR8AZC591LWAV&8GT134\PG0FS2W3&0PTGOTQE58DBRBXCETMPK9XA3ELI8GMIG1YHTPYO3O8709/ECCOIJN144TPJIIIZV773QQV28\Z8A2M7HGF64E&7QA&OFVGJM6BH1ZUZNL153BGVCCCP7R8B3WAU2U5D24QS5ARTLF40EHEO7RLDT4O7/AQFZA95TXD\Y13CXVD20I/WSZ0LJ2X/PVU4WM7LI\GTDF2F0JS/0YH2C7ZAMYW4AFVDG\TL15U1BQSM9UYAJZK4N521Z7\XPPS/WZ&22HI8ET0ZPND5AWUO842OJ5Y769MZ/U3KU8KCRPZ7ECLM3GX57EC49YS/VOBHGB17X6KELS/SF8JGTLD0MT46R\N9QNTCNR0COR2/9TUPHWZBOMRKLO70J8PYSO0\&7F0HH4BWF36&PY8LMUE8J4&WA5TBDSV5VQNRHUP0FXB17JUNF6WD2DFDHOLASZIBR&LQMSMWTVYOVM\JU3M1IS0KL8Z6IOHTO&J7\DA0TAWHR4V8PCT2MU5&MBFR6SOEOF&VCELQ3ZHI8T5UN3RG8SG7HKV/\V6AYR5M4&6L4C&0MXD6IXECBHJ8&EO4VNRH5GWR0T2N/GP5TTVWH21NR4&RI/NZXC2QY47FBYG283E85QPSW4W6YD2BHEJ2GC28Q\H1ZQVVV&S0ZEZ4U7D5S84UB5/9PQV5BJR6I16GJAKYYCODSRIL&9QUG0Z6SZGFQ0ZQZ5W6A/WRXG9&R7Q\HK5E59ZVBA0X7FH/P/QZ8PKCN\/A40OXIH/G7VY3GA4AJ\WS\WUQ3C5&347&Y4OYCOZIBD7M0T7XJ5OORC5D7HRFEHD343VJPPGX/K981H2KII2/PSUV\L489UD6&DV//XI7",
@"Z4RHF/OZRG99RFOLI&LEYK0PGD8XZ5NYA7LYANPB9ER2YHO62J1\MDJODCACB3&Y6L9X72L8WJHT6/4&1C8QEOL9Y/U\MNAFE58MK4&A/6OC82UGKBO&8VUS&&&9HMVJJBOABR29C7TLAJA8PO0L\BJVLQNK5C5XKF66OTE6MS9BCJR3&ET5YKLI562XDREAB8A8QGU9J7&TEISC&XL1VA\A6XBV4U27O8&HIWN5XXW4K4DWN0YTFQRB9AB5E\F2FEEJJL6PKSD\QH2BUSHD9J2\R/LHVU0YS6YGZ7NC6IJZMSX1L&LZ4B69PG4L&Y725STXVWPZFFK0&CY\MX9VJB7RA23TCBCIOT76&AF2XYTY4F9MV5\O1LT3YCW658WDDCMTI5&MRH\XUI076R/KD0TCAEI/QM91CQV16QE26Z/UM8IPO2&O\MAPVJSDWB8FLKVE0\AQMHQR3E85V1MV32PFGX/AG534JCND1Q1WB38WYWTOI4TG52U51V4QTLBY034EEA3TA76UWEV5PMW&TVVPGYKC31K8Z75XQZOGBJTBIM/TZMD&JFIP/S202LW/72L/O2/P/JBXTFQ\FKB/50X0PB18ROTHO\GTB&E/O0C&DY85C3VSKZFGEXVNAC\V26IV/FFEWEXXW4F9606B/26&PQQ39M2TKKPN7G6PMGDAWTB4IEIK219T2\UU1PHJPENMO4C07Q13Z5Q8PZV5DR3VN9Y8YM0/&6YRF1QRBVQMAF79UYFC6OF/N5&SGGBU2345HJE3VBRUHB1OAHYDY10EN2/L8U8WKOB2V7R62XX99K4QR5ANEZGET7P\L68AF7J6A&5G25NAE4IC\U6DUUSYI/I1RTU92W3BA/PR&7XMLFA2ZN&4&4TYPYYD4E1JKRLUAGBBEPDZ9GMC/TBET2//DFYPLM08GOB76S1SM[=12=]W161JMWGKCW3UTOR8VZ242HTVESIR5V5UCOIJQOD2GP5WYTNSB5/ZJ96TMFE6N2ST4ISFFHRG",
@"W&YMO//YE3P&YFLGU2/LJJPR/M5PAIM7N3DJLTEPIT2WMS8Z/MXQJG/MWGPCFUX8RVY8BB8AXVC3U6ESQFS1Y8XH63ZEEBK186F46AX9RW51EG53B9Y&B9KV/RBKO38WKO700NYQVWKBC8DZ/9CHPKZ&VW7P\MU01JQ2MFC1KIRSYJSBNPNS10GA18EETJSIBWN6SNN56O9H6HNME5BW&C&ADQBQA\HB3IQC9ZWACUZM3\GUV5A0I9I&XM2BM957G8RX3LQRJATSQZJFJT8I\T57&RRW9U0F14F8TW4JOVRHP3V/DX46AX9ZDXXL67V1MN3ZTOY01Y6PCXRJ8TSM37FE8T49\SQUA28B&9R2&EEP4TXSFNQNOI\RIZ4AW11JILPM2PK\C3NY33NO9L3XCCG44Q6NFQFKP7GSEK33DRKX8M1SMPEK\DHFFXVMW/6YXDJ9W8KYVATX5V9R2OA3M8ML0AMT2RGGYYA5D48RFS2/WWNX0DXI9DM23/JVV39E6N&GUEO/SWX6GO2D015Z7\KVMLBGVM8OWYDJXGCW1Z2NSSVPIG86/JJ7CR7JDIOG0JKUKSSTZJ/HJ/C62Y\PQBQMOIHGM6STLVZIIBE20OH0MCYFOATRJ&2Y5/GBKLH54Q90L7X1UI1C73ALXC5LNBJL6AQL7CSOHP98G/6UQ5/BK04C/7RIT8S3HX7KQM6R3M7R6EFZIL8UDIBGIONAYJ8L/G1VDWDD\SK/5NI514AIA/Z\W1CCURVUZQXWYH4WY\DN8FUL7I0L&U3&OUBEE03TJ5WPEIOAINAASNG9RV\L3JUF0YHEGZR\HXECWFHZ70DZT2UANE0W1S2&LQ2SAK6V8C57JENLNMQDG8Y/EH3CJ27E3FQ1YX6U3R/Z3J3PIOBZ6Q54O5T4XA5DAFNI8Z06JYEHARQULWZ80ILNNYM6EC/2Y6ZY8VTW0IPHLY49P\SAO/Q47A8JM72H1PVG55Z3CDHS5DB17PQFW9O0Q7380KJ6TIS9CYEXM2/",
@"K3\&3\GP/RWY4A72\B3D57N\WXFZJL666&D/S7&9T8LP9X18H8GVVZFQP&PF6TGZX345//KDB7W/V\B&9KSNFKKG60VTS6DA2Z4G58\JYCT1DH8Q/QJWB5UMTX\KP4YI4VI8H8GBLI2C4WDY4EVBXT&9FR0H9176RL/U&&JCKHK5CRV9UMSKIWXKWL32I\EXN8YSYVZ57T4PJG61930WJXY71ZJU6LDZSH6CL&0ZP25HAPRB5RLUO2K44\W\VNZSMW1Z87S08WI9BTZVJH1PAVL29CKMP2DBCN7R15G\&XY5UN2LMB1OYKR3KWGKGSG61YI6QA3QQ9THWM&&OA2Q58DG2CNP6MSMOUAZEHKO87B644GTWG9F32B6VBEOZOWDRG6BLN8H2OUJO5ZQNWYSHDCD91UK\PY\EHJL1POID&L0FS5V9ZEWHWDJ5D6ZA0873A4ZWO1/HQOI5P/R8\NMKB3VD&SYW2HPEQ9E0F&V/GO4H8RQFP3CNWW1KIVW8DOSI&EOS533&4OEZ&NIVCSG\FCV7I7SXPZ758VI3C/MYACVHSBK7MB5YHUD9WUK\LGWFUL3RFSSFFV/CUNOGWXKN6IXORLGV0ON7TQZGK627W0SZWAPJFEO19ILL1P&6L9S3HDWE0I827P4G3Q9/QVAZ\KEOR878WZI1RTRLV9IY6TRFV3YV/NT92VEM&M3A8&6E\BTK&YPTNP5R5&61KM/IFLOFLJGI270MHTJNVM/AWN30TASB2VBX&ZCY97MGNEZS5MR93YLF2YE1YL3ESG5CNUQYR1&40S048AHFX65PM7/RTHIBPIYSG1FK96SCZTRK/M5YDXUZOP3TX\FJS\PR6HYG79J4N236P0TGOX/41&E3\Z0/0JW1DAQ21Z3GO3MYZ/E/S&77AX37D8IIJLDDGB2PJ3S273Q\ZSDBV3S1P10SJWZ5RU/CZISXH201TEAKH5HY4G0T6O1ROJFZEZLM5NLRAS65C4HK1QLRPBAK6RJKTBJ",
@"/WAW760R7T2YMM7QCHR3\0KDZBTOEB\J9ICHNRA\R\ZQ1/\BGDBKL&92TH5HD2S4ZDQYN86A2&U2XZ\DUN//91/9MM0FY681S84YTM0LJBVMSGE6J1Z25U7/FUMBH0O9E5J28NWHZZ18FYRFH69/GF9\B6S&AZDVZYIZ/P/8FSDF5&4UCG6N4R3K1C7WG&VGIUQ5I59A50C3FBB/96624H8J2Z18BVLDXZ3KEK\BR3ZC9GFZB9ZNG5PAYGCVDB&JP\FTL36Z85LAV6NVUC6E8\/5K2Z/HQ/Q3PZ/AZNLDAROUOS46TBBH8ORBNJWE9RR77JFGPU81VA7TVL8J7E0P9J7BI90P3GHWAUZEMYR&FMZ7T/SCNMJ53C/YPE\S7S\O6LTBY3/JZ1JXX&UKQYCQ/O6/WA2I0\E0OKBIRRQXPAFB6NBPX0CJQURRSWRXA2V1XWJM\L6&HRA9J4DI&NXA88K66W38&6W0SQRKE2QL6DB\TVI0SJY0EV51MPTPU\&O8NR6N6EK9MG56LMKNDQ3I8W9X2/1JB38D0CGEPNYEN34PA7ACIBRVIF&3UIX8PB8VL1GIGGY7E4TX8/YA&LN7UDQWG221M8IEL149BC13XL7\AX2A9K/7YF3W5AC9UJWPMGF2&9XWKJIRVVA4\M\GRDZGRK0103XPYLV6BA&ZNWO9LAJAL\ILXJ8DSWUZ98XSXC/KR//L&M57127QB0P1UM5OQSNSTN3S&9MJD&VNB/LLQAO31DYJS8/KJW7&XR4YWN85QYNCECZXAT\PDX3P2T&D\B&UEW2WF02CFWMD3WEQJNK2XR8A1P9CO57PY6/UNDSN48KUK0ZGPW6X4J901282301M2/R9YWCG79HO2A33Z4\JYO/K6XH2XEG/5NI2U5T037LHSN&7&&A/OSMD&O3R\FM6VKVP4AJ7LKT3C24SYM3XEJWMBF3FCB2XVSYI4WCGYD&VAJWK6YP12L1JOZKD5JV8IXEW1BJ47/XSMSFTV4ID",
@"I63MUUIQ1ZOOVEMPFAW4OY641I98T4VABRZP74CG66DIWI9IF2OVHQ1X&\YLYM9/DNNDR/VN\Q\VUYHSL133P&5Y3CP8G3VT9FEJ864HHBX4RGCO4G&9WGUEU1NOVZGH7RYOT\WS/VVOPBGW&AE&3Y/3YA1GSPZV7P9AU085XT&BXG2TV3PUUHQJU83SKPAU8AU&EGCMFMPJY8GSLHY1AFA0&0SY/PVHTSGWY2PP1COI4GYZ2KHC3MU3A7AQ1QP33I3G2W6V5J&/3485B59ZHTQH/QW42[=12=]L0YRWQS9FRZJUMX&I\HO8T3WK4WIMAB56V1JFMMPW94HUJ97NQN6UW54/BH46JXFP7Q&XN68Y55VBB8288ZIKJ2/MDFVVMLY5Z59J&XRI246BPAF8EO1TGXGJ0B23DKS0E2PJ\S8LHAVS99/DAZR\XFYCY0WERMG/ZX9/ZTQLGB1N4DY3Q5TD\DMXK89QT8DF2\KSD24SG6SA9N57IY5D\VLLZ3W&5K\VX56FZ1BB9EYL0/DBHUHRNYA2H4CB9GBHCO2ABCL&X3H69&Y10U5KDTI&4DZAF2DRIMIC&FIH6WRH5IGNNOO4DWF3I\ERNXYR3S3MTYUZB8ZYUXL21LZ4OMNZGS6BA47J\&QMR772612H9UIYZO3C/6DRFEFB4SZJBQZUG\K7Q//ZWF2ZJHPYB4LE9&GN15/NCSFT80S0E9Y&9R7AOT4WDBIKEUYG5/FYAWXD&J3V21UFGLISFG&HBOKAK8ONCL8H3A&M63AF2I6OTDD5LFAY//XYMW6D7QTR6NOGL8YPF7S5U8UH4WB9KKJ6QOAK9/KM2PVG1/TQTYSDS4EQCZLLOWGWDV2/7OSIWFCFNNS7CYQY4GNYJXIJY&\GI&DFHWVFGJUM2&C1GRJ2GU4/IE1KGIXWH99OKNZTCKSVYA9KUTDG3IA1IF/D7L\/Z/F6D1R65308CILHIQ20FQ6HFEPVY3MU918CH5BJOAUFY&638QWL5JEH/8WMR",
@"JE9WUMXMFJ9Y9B5Q3WFLZ0HHA20W0FLJ15E8YWE0JR2GZZ9HL3HMQB4V/2V5ZAYA/09D9/5HSSCI\AVN5SL//&60AVALAI51IKO/A6/&WX9GHAG21CJDNGGR6PJ4WXAI9&/F80Q\C15L7SEZKET19QB60SFHOFXX&E5\V0P9HN8XOKWTRDLLT\ESPUJW/EHL8ZQUSG/BTT6S48494YFU1ZM3AMVBQ6&DFW127BBKFJ4&FY0U3M5L[=12=]WIM0UFY9Y0U3MHGBB2W8OS8MXOYAKDA0ESATPHU8ZIYESPMTO2LC1DLENACGTXZUZ6Y7H0Z7I1JG737ICFZV5\BG9FPFNOBWERY3RL0CR7A7FKWF6EO\E118W1LUJ17MHX2MISX7\SOE/HAYVJMJACRP33H3AG62&1ZVUK/OTU&YNX/P0Z\APXMFFNVRL665ZYEJVSEKM/3SD5CG64DNH5MPPUQG2SDZ0G&1S07IU11R76BMKPYT3TY6M27BC/V67D596O0G/85TE7UVSD9M7W9GVGP356GWF7X4AET91SV80F1RHLV\BI&KGYOZ&9NE1INKK3VNXAYPBATPS/WTKHV98MXO3694ERGR4RGQ3HOBXXJGF&HBN66U0RO/GGX3D6KW6BXA4F3D6TLLDQJ4Z8RKXZ4NCIKWXY/4MZMEOGKHD31GFD72/6DIO&\HKK\V7GTIVU&QEEPTXJH7\XH&OVZ3U2PM0E7EI1M/KTYYEQX5QXXE5EJZC\GMT206EZ3&KLL99KWR&W8\6M/EKTW8HCJUAQU54UR0YVFM1IVU40SDIO0P316GHECJBO96BZHCQLMKHXQC/BDUWFMZ3FCC1LTTT9KMM1SFTQZ/BPIFK3IFAVZ9CJD9WENF464KND3JV\BFSOYN9/5/CNT/JNKCYWVOCUFHX/4G&&XCUUQ0X2AZMPCRM6B&61Y&PZC\JQ2\FY\D2RQ2/XS8V8B0R18495NLNYZ7RSRGABU1R&28PMCJJ3QUXPUUV\CMK02D",
@"4VKRFL8UNNIR\&OW3DCXIFJC/9YB\IQ4JYD6CXD/78GKGCWWXTWGXE8ZMIUJZ6VF9RIN8UUFAE2M\87NBRRZKGE2RU7D7LBNAO27I0C&QGTOW0NMZ8XPETYLDXR&0CF61&/XGAEOOSIDZ2G3HUR&0YJU2Q3YJCLOB00X33GY4JBYLVYNR05FXGFD3Q72JSELG6C&CWAQO5HQXXJH5QHVJG38UX6M9QPLF2RRSZL70P45TFHZ/6LVBADHRS20U/Q8L7G42FEM87OE1FKTWAW0QNLI5FA87OCRY&P/51[=12=]HYEKYOAVJR781G2RQ9MH8\UW7OS22N17B9T5IBWRERYQUH3SJ\T8P45IEVQK9L692&64Z/ION7CQNEBZXAT465SKEK00YLV6Y20VNL3EVU1O8&T3085CC9TW0PJU3BMI5YRTMZHHA1K/V2P1G8YZBWZ3B4KQCIOTITWKUAQA1XBNZWA\&UN8Q0HJRVO4E5N42CFFGGRX\QULES3MQU8SDVLNL6V8Y9TJ&76OHR51310WCOX981H356MXV&B/LLJZ4TWG0BK6VYYKXDWV9MEFYH&ABW86Z6QOMMAV4QJ6QOIHICASPTB\GDAWUVEEGRG1HJ/KCB3SDL2K&54\WPQG5SHJLQAILE0\ITA\F2QN3V88O3X23GU3AA92C0\YAUG\X3CS5656&DQJWL7V6LSFX/\HWK9R44NIP9LY1E//N14/X0F36Q51CAO0579U9OCH3H60AJ61OU58GAX8EGYN&YGPUY57IPB&YWHP7S2WWDNVISU4JAP221IEARFPQ&T&T6KW6HBZRB48LYGCEBYHALJ/NCOQNNGXWOBPI/\B&3L0/N6PKDLPOM\HWMJ36YMD8GL/W46GDWHK&W&AI&FJB4JKP7580HIOQI43B96SJEM4E1I&MJU6SCBE/BV2&/T8O6644J&MF0A/SRF0Y5VR0O9OGZ6&OETLYQQL8RIDKI15CEZS97DGOBH&/SYEP&\BG1MBB74HX",
@"SHS0ELBANCTAN/WJQNQ6D0KKZYN4YQCD9V962M6GWEC9RB6425YTOOU4/IAS/KO9AQD4A3TDUJJ\YN5Y4WB64W1VAF9ULNIL2F9A/B3&LV\EEVFWPP1NIUFR2U387GB/ITR4026BUJXWRS&MF8Z7DIASLPL7FN25DGMZFX2\UGA86FDL8U69UG7AT\TKRHU5TKFNGUG0N9HFYGM&&XU6K9LLFGERUVK5NBZ5FVOL376ONM\R&M00UW&6I&Q2F4YP4XUT6QJJDQDNT464SCW\E0TD6MNO7A1CNQX25SYVDRXESZNQGZKDI0KEDR0UD7OC1B&CHD\&RA80COXH&9II3Y6ZFSZO5ERICVPRZKJC0KYH4WB16SVHZGLDHN/1RXHNV0YU&GU10FVT&Z7VQ/UMVKV8JMJMNUYCDLZE\U20/6UTY5EVSOKTC74LE2K09INFUSQ1&2X9I7O22CKRH16&KEAITNAIKC31SP\FOQV23OLHSCVBR6SIOO8QSHHZ2OYGDZJNDEC4FEI8552R4QWVNDTV0HI9AP2FE55I\N40CKF&XZR273XIWVMF6VQ8VJE6G01/ZWAQZ9SC\U/B2TBK4UWWSZOQ98F6FM69\UDK2GV0CJHMXPGCH7CYEFR&IXU43Z/Y0BDHP3UX&9TIRB5T2CYLKI55DDCFZ49PMVYWM\ZRNRZIYIUG4AB1BYOSIKEL0P\IAE88PJH3PGVXH7V8NY2IO1HGNC7O3/SQIUMZ4V6KL70V9YCJ25BNS52H1J8E9BQANFOZU9E54R9TBYJ2&XYF\Q4F/UZ1OJRZI4JP250JVA8IGD&GFMPREHGP&XGCDZCOPSSW85LZX/UWVSWB7&VAXKUM6CDS/IF50U1VRXGRXJRLRFB0TB5D6P7HBV&IWE&LQGGA4BXJ5DPO6I80BP&8QC\LZTT8XTJF8K\B8SQVK2&TN60LHGFE8NH8OKU2Y7I9E1MX2&TUR74ILGF0IM40NFJVCDZY/19QUDPZTCWH0Y",
@"ZBV&XHE6UMDUV\S4VYN8W3/O1H4THF3WA2TI&DSRTDGXM&UQH1U/74B8DHKPQXZOVTT6SJ5RF8PSWNB1ZNMTY62J0XE55CB8R5B6T1//9C4&PWM3FW3DLF224KF8F&ZC7TA4LII/QPXWB37ELOZJM/XLCMCIVC49Q1E8VUS9N508VG0APBX3NP39922\G&OOX1GNY\V3929UK139ZB6URAVA\I&65T3NQMK7&NORT67XTJYHMEG79WFFPP&2/P&VD\Q89MZPAXG\U2X47&HYGVP027/&R38SY/FZ3D/AR46LQGY04H8\INOUW2FBO0/K11NWW\B3CHHP1DKWIKHK8/KKWXCA/8Y37WX26CD6GE9AF&6SSW6DT0O4RCAA6HVQUFTU3FHOD4BJEW4XVNBVKGH5L3CE/GK1S2R1&/609FWX3H/QHLSSFAGO/0J&DCQ/TM3PFDYXTNYEXXCD5Z/Y05WSWD3L17X61ZDQRVLE08OB4NXFGRF4J13L6CMM8Z25P/TZZKO53DUMQ0V0G1/PP0F1I4N&LCWY66\T8DM6Q7&IL28ZN&WDSUE\UWFAX6U0U9SX2C5COD\U09QT91ZMTSGL2A\M\MIXNM0PJL9KHT2OVWKXFYE9HHHB3H72ESEB8OHOIAJX4OF&242F2OGMHMQFEZZCRHG1O0THP9OFPUE5CHL\R1&2L56W\BJWOGGWIRYCLV35&B/0IXD/N0Y2HQPW6/JOZ43IOUXXWJ08\H3K7GON\MJ0VQO5BBINMOGHK1M0ASND&33AZE10W8QNVD0/F4WVAMVXBVAF60NS\F050OF9MV4RZHBPUI95C0HG&EEV78V/OPP7K4ZZISVEYH86EQFEVFDAYTOA53099BRK4GF3VKXWFCV4ILRQ2QOIMOJ3PY6R4YIW3YB/LOVLVT8V\W5TLKGSZJ\Q9ON/QF5T6\BXKUEO7CZ6S1566NGUS2/T0XA9BY8Q1P1&VIJ4F5XWWE/IWUDD&KADBU9ZUIMJHJFD&5LYD",
@"PO0EN/V04MTU4RQOX\ALWK9SOPN&7J4JS&W8N&0XN&2961P412O6KMUFRH3\WV6VUKC57UAYKP/WUAZ0&VLE7\FRRRGI2A5GGOWYX/H12V7P/XQVD&AK10WL/NPD6PVOFPNZDBOYDQFPE3U7AYF3&UST5L1JUD7MASJVJ4SBXPGLVGHH6VDIK5PX/774NEE&V5PYT\XIFEFXOH\YDUQ\AZCHDYXP901SKG223W07/7CFZ4J29J151F&82HU8NIMSQZMHRI7U7VAGW/VMO8T0&84FH6&VB5T2UW2ARCK0OG\FE5M5ZHTS2YTU7H&XILTCCLZ&HV8MX5M59ZAPUH96LB&8DHFJCZRC09C6GMYEMG7/M0YIHXDBPZ3AL39APYK/NKF&WHIHW4TFGCWPW/CSWQZAGCUQQX1199WCUYY&O8SYFX7IHTRSV4O/XF6UZ54\C5IKTT8/LCD0/A7VHLJ/GJGEVZRP5ENVEUVNOX20XTHS10&WKKMNW646YE26BTEH2UWQSUGXWVMZC1Q708EV4&&K222K88ZEP&2GEWE3D24BTE3/07GGOWQ3VL0259209IKC\J2D3NSCH/4X&4WA2S25W\X68P\G&EEL71\RECPAEOVXUC2AM2\QSRT&Y9IOPLCD6S3L5F8ZD11IPAL5Z/7KG06PI&5I7BY6LS4CLRHH6LN33KWYXP1RQ4/FYOD6N05BD89/IJUH3ZR7NDY/PGXRMHPUVZQ9OO6GTLZ8OZQO8T13NC4V3FRGCN29SPPW6X5O6KOCQ3W22JV5SYGS78GJ/0DFW3P\K6UL1M/C02E&W1R649Q7I92/QWQGGJS0OXS91KEF0D4E3GZJIKNZMU2NEX7E948RJRY\IUEU4KGEEYGK9H/996N67E4EPAJ8HN7MU0B0F58BNXJTQXH17&VQD5DD3AE4BL93372IGJ4D\LSJ8K055UAI4QJ2W//F1DAC0S2W8\VYISS5N7ISMM&TK1\NXAZILZO7LPWPVE/6&PAM/RO22R5PEU5&TP\",
@"7MNNWDYT/K6/HOFU80ZPGY9T66&33XW8FGCUZBRJM/QR8UXA&A9M7A4JQ6T2D73N1/5BMY76JQCJHRXMJ&430KBFO6D5V1FRGD3V0NFDCR/UB&JHTDD&ZR900TUBLUKXCE0ZX0MQYWHWH64EWOIBOHQLBC8H6D5VGMR/LWW64ZODJMS62QS9LIJ80PXV4FXU4YQ8P65&4PK16NB1WCRPY8J/CWK9&BBZC6LY9WQ8XSF9\VBMN8H98OS55W9A2NXYABQ4AYW4F3N&UU/WDDL&79QJR4YL1SQVN9BL9D/EDP4FBTKLZN9YCY3EYHNJALDZM4YYTZZAGH8SEKH\TMZNW4T2F9Z131E4LF5K8Z4A09S82L&NAP30Z3DUK8TW&\JRDDG&S9D6VZ00MY&6/L1O\QFVBK&&GIA2ZA5YFA8DL9FACQIZ8ZZ1J8TZ\X/H/D0NY/AM5O0/PYCBLFSYCMDUVLT3UG0VC1GIJ4OFP86ULX6RN5EMEXAG4NRJ5Z0F81S75T3NIGSWV6A8/C57Q2WVHDAB0FDH656WF&Y6B3D\EQX/MWM2762FF9Z2T2ZCCL22AQ2\Q&5ZZYR4SD1E6ONAD1RJM9NMDA8508/86OL7ACTUR7KPAVJ0YL&TYUZTVY2ZDXG5LSDSABI94SY/LV4H6\JY9M33ITT74540JIJ4XT1XDC2G81IA6U5ENU9&2MKTUNF&0DLAWNJZV6XW7TLTAJ&ZM1LKBLIIC2/3S/AF16/S71&COFR4IAM8&BZA4A\LEBW597E/SF5HMT4Y1J996R&BPC3RKAO08ZO6EGFUAULCIFWSJALUECSZBVQ7D0ZS4FMZF\TVDO8MF/6KTLHK16V5G14W3LQN76KD69NLU3Q3GGUE1FO5SP3\WTTQG/44\URLZ3RW\P5ZAHZ7X/Y8RDMTMP9EX\Z4Y1IS7VZ5V47TJTCG7NZAIMKEHB5F&3AAL\H99G3N4K41S9ZXU54R&1AF1WX52T5447HLMFJ1WMI/VVY",
@"KPIXH&VAX/CHMV/XLR&/Y1NKPVD80TDWG\MQT8Y5I6XOJ//FY1/SWXAVB/IY80NE7SBOJUEP6G24E&BRX/J\WXAV/4OV0&9VSTT49V9EXUZQ8IRC94A\QPVKSTRRFV26JGMYTKVCBEOB\X01MMZ8\ED\JLPER\C55G196VZJLATL852F6867KCIZJ\F/XGLIFQT3&ZAB5CR/QWPMFG&Z1GM1DBMF2LGS7/YC9H7IJFIMVVVKAFJHUMDMRLV&2ZNF4R0DK4E0PW/AFVSBFWB&/U6LYXY8TW4DUX5DX/8RC7/UPRFAT0U4D4AIXORZGIG547SV2ORH1X9DWM9HSYO6BA&2WXTISJL70E3U\XKEIMCT8/YLSKHV6M3382\F8I2SMCPSWOI7NKY2/S7Z\I3IB2ANN&ZJYFJ&XXH6UG1DCMHW1B6P8LH0SUQWBBEX2&JIAYENLBF4T0F2VQYLGJOM\WUDHX4SBENCC&WD/TE6GPG4O0BXQ5RTY9KRDAG0J03ONDZV7VOZFUFVP32TWGCI07RF2EA9NQXTY4RKBS38R4NE41BNLZDCYU1SYU53URM19Z9XLRSEQH39TNOBC0Y0MV8ED\ZU0ANARYHE4RB7H&YQ34&LF4076ZPN45TN5\RQ63S7FKJYZ4SN/RNL&NO8MSH4J6N\/1BJVHWAMEG8UCIBGCQMSINRWVEOW0YL9L0J427M&7HTOKKFXHPAS2NXZADIQZT7\IOKM/K1SFISKCH6DRCQ895/XFW4YY9MOMVF8A5091VNT7NW5JF&WC&BQQZHNTC6J9E/UB/DYOUGOSR35A\PT93LNT1SNYNQY1DX3PC4MCOIV50\&9PMU0NNF5WAMS2&ADUZO6&P/HCRVV3V63SRJA8\O3R/5CR6MOHRKAWG9&PNX94XBBGWAL3&IWLXOBW73IEHNLK5GLUJYVNR4876BXHJ02QUXO5XJ24NP14UOZI6ZTF5&8PDWGCWDHTZ6D/\ZOXGAURFJD6WS8ML2XV",
@"1&1AD0HKHHF1K2JHK9&5RQJ6TMSEH8I9IVJ&/OUS5KK\EPV7I1BP35EL38T3HCCM\IS2SKJ9OT&HGL1E3Y9T66GPQ/IC73L3H/&896O/SFAJ5/ERGPAWGWSECDLVCHCYIJ&IL5I/J\B169WT538S32WXS866U68LCPBW/9GOHCMHV4LFT52LLX7TZP3Q&OPQD2YR8AV9XUK0QPB0X1N2EX&SUV9VG3O508E5G6JSK504MGDKNC6KB0MT3F9NDA27FRAULJU3R7SL9IFOSZHD9D4AWYCA/9OJC6Y7GV\EVD6GHAWU&V8Q5Z/B0&/0GT6USIIDWLH90DV6KX5VBUAOB\RQ8WHGXL/BKL0&5SNDD4CHPYZSRTU34IAEALOFTW\/63WWMACH2N45E&I0KV54GIAK/XN0OWXU5FOYCDGQRMBRQH&BC18/4G4X3LY10O6G2K&&YXYHPON6GV73XLXZ0Z2ZO373SR3CT81FIAQSD0VP6/QHR8EO4GSDUNX7272/YKNL71UW8FWAEN5QN0MXNOLMPYX7PV2I\X4VXEN2NUTZWR\HVHUCVFXJ&A9JE0HNPOCTWJ5IMXK58Y2/ZQMHAZZ5AUWWIDXZNGJIPRXLPL2ONL\W1N&M32JTC0IAI&XS2PUVH5B5190/IFILKU9MN6TSG/VYGLT&LMZQO9MGX6BLL9R/21CKE88BOJJPZPP1Z9TJT6FAAGJ0R7ZZGIW59AH3D3BEZ9UHQMZPPHR9VCK/ZIWUXWIQ6X4Z13G25ANDZBJEIKKZJ73JE7GTUC0DN6VA0YB1DV1GLX\SMMMKZHN/8SZLVLSLQW1QWIXY/CW1FX/U81HI3QQGSXEH&3F5CQ228V8D21MWXZ4LUFP7DKU&FV/\DPYG/3Z27IYN6ESCD7V556Z7OL1483XNX9&MCGZ7ABRMTCA&5S9K&EGK345ZB77EYK29EG&/I154ONNMK2&P6MNS31WLNA5FHM0JMD7YS\CLMO9PQTOM8RKM9JGPX1WH9ZWC",
@"ZE&G8N97JCGO5G87YTK3COMD/SB4P7OZ562LTHQUUPD7D4WR61VQP6&L59JPMFSO0TV\QWNRC3IZKS&F8X[=12=]M\K&7QTX/BHO/1GWIXAJOENYXMAN9DU2H4C1JWE&D3TBV62WMQ/KW1MHXYOUQG17TSHFZRNYTBGYXMD3WRBSGJGTS7EXIWW9BZUCZX97DL4UU0WLUX/\FI0JM1Z4N2Q9SJWAE&VGP8SYL5CXZY46\L3\/EUN78CKEXSUS\P4027TU05J7R2AUKGBQYCAWW100NVE1I6AFTDICYA0BYH5OX\JM9&M34HDAH6HE1VZY27AH/YP&\O9LCOL54ITKOM&I845VNCVGZ2\CO/H0O4J1E835684QEST1I2DA57Z862ZNQJR6B68WCKDAAA1RLEBGIJ7Y7G7UFN8PIQPXR\PLW/Y/YDA5FHX10SEGO5\OQ2P14WXEAM22XLY9A4GBPG12MIIY&VNIT9V/LQIAGK&/85VR5G09\S&IABKO9ONGPO41OCT36O4SG37T03657RJB/N/KG6D5/5VTB6D20/CX1TBJG31FVUM/F34BFIXAK&VOIOS70DF9OZNQL0DPF\JPSXNLBCXSNCM2[=12=]B5K7SRPPWTPO2RFH7M2F8XAH5XT0WMNXRYZKELS5ADB78ZNFMFH&A64R5DB7/16JG4/D57CW79E5VFLFKONQENXX7IRBJX7MJ41D2JNSDYFD2&8049XWOPF5HMJWPBMJB4V3RIPBA8NSIU87M4JNALZ89P&3CCL8B/QFIWTVVSBZXZROKX4&J360EVLABK5LGMS/QHW06R3S5&LJ\YTRLMZLD3BZKTUK03SKGT/CBDF4AO7EKCBQ4OA70H70G9QN9S5CUBCR0QPHG7L189PIRETL3YW&ZJ9F058VW5XJ&X2N59F5JTH85\TM8RD4QUKTN&2FCMGJ7OFN//3DURZYS/CWDT1485M60MN6G&3/N\AQ5FO[=12=]AK&7ZAQ9GBVYONCCMZXW/9U02K",
@"U/Z4/E2E8UN\BM/9A\HL\Y/OTS4P2D2LEOTSKPDR8KRU2NYLZB9WTQM8&KLSMNO45B6Z6RYY73P1GQZF7T21HG51CXT&EYEV9020T\SIPL23AY2WYFX6XZXZJFXI/YUIY74T0\Y8BUM8QB0R8/O\BL\JCDROOJK34UEG6I90U24CN1IHSFNAKVHN8VQWUKT4KWE8/TYZB1RLT99O8J8I9JSIN4LK5MFJJA43WMK\U0&WE87\ZB1KOK8BD9VGIN61VHCTEF4V&/1IK9DR9MY3Y87\E3004E3H6LB96O7UKGLRWZ3G5DJ82DDZNEOORD47GUPHYVSDTSXPPS&T8087R3HOW1ASCGPQKCK5LYR1PYWXC/28O\ID&LCY3UY9V&BMDGFMIHIKIGR5GXLY&EEE/LQ\&YB3AVFQXKU85P0H26JSGI&9Q89P43GNWGRJ0BBI9CQ6XQ/P&QXF2G7VAY2V083FZCDAK1H45BVE5GMA/UQNFAXQM9JBLTVBLLGVN9EKI5M1X237M1XFSP&YRZ1OSFSLTT5U&30AQFEM085XGO2X9PW9LVD0I24DNBID9J8VBW1MK0/V7DIEP8PD/9IR0A51OB&Z0109SHVM0KYYXU6ETZ0RYEG&AR8B4A/I0K7FPLYINCQ0KX6FH0H1OUBWV19BLUV0MQ/M002IAREV1T2QY37E6J7FJLW1PX96U2N7ZTST\&09QS8C&TPVZQ6CV5DODA5PULA\F73ELOG7V/23QU28INGD8KL7PDP/GKOFR99E2KKLK&UYCN\VK/HHF/C7W92I\I1KVXLTYYG/D7593Z4CE60JCHAU7CV6VCMCLJDSBS/Y3KDKEGD9EZDFUSINX3YVDMOAV3YUWLAY8BS5E2Q1\Y18\HU6B28K6PVQ9C2NVWM5YRJT&PJ7N/WRYSCNJ4T6Q25TTB8BACGPL8KU\B6YTB/95D5QAOE3DTP8Z3A\UH6K4HF2IUOHNO590PISBZ\PM5TO7IB7EMI0EY/DIS&94IFAD3CX2",
};
[GlobalSetup]
public virtual void Setup()
{
if (!Vector.IsHardwareAccelerated)
{
throw new Exception("Vector.IsHardwareAccelerated == false! Check your build settings!");
}
}
[Benchmark]
public void HasWhiteSpacesWithSimd()
{
int count = 0;
foreach (string line in lines)
{
bool hasWhiteSpace = line.HasWhiteSpaces();
if (hasWhiteSpace) count++;
}
}
[Benchmark]
public void HasWhiteSpacesWithLoop()
{
int count = 0;
foreach (string line in lines)
{
bool hasWhiteSpace = line.HasWhiteSpacesLoop();
if (hasWhiteSpace) count++;
}
}
[Benchmark(Baseline = true)]
public void HasWhiteSpacesWithLinq()
{
int count = 0;
foreach (string line in lines)
{
bool hasWhiteSpace = line.HasWhiteSpacesLinq();
if (hasWhiteSpace) count++;
}
}
}
public static class StringExtensions
{
static Vector<byte> spaces = new Vector<byte>(Convert.ToByte(' '));
public static bool HasWhiteSpaces(this string s)
{
const int registersize = 32;
if (s == null)
{
return false;
}
int pos = 0;
byte[] bytes = ArrayPool<byte>.Shared.Rent(32);
while (pos < s.Length)
{
Encoding.UTF8.GetBytes(s, pos, registersize, bytes, 0);
Vector<byte> v = new Vector<byte>(bytes);
bool foundAnySpaces = Vector.EqualsAny(v, spaces);
pos += registersize;
if (foundAnySpaces)
{
ArrayPool<byte>.Shared.Return(bytes);
return true;
}
}
ArrayPool<byte>.Shared.Return(bytes);
return false;
}
public static bool HasWhiteSpacesLoop(this string s)
{
if (s == null)
{
return false;
}
for (int i = 0; i < s.Length; i++)
{
if (s[i] == ' ')
{
return true;
}
}
return false;
}
public static bool HasWhiteSpacesLinq(this string s)
{
if (s == null)
{
return false;
}
return s.Any(c => c == ' ');
}
}
}
使用 Vector<T>
的代价高昂的部分首先是获取初始化的 Vector<T>
- 因此最近代码使用的主要技巧是欺骗并使用 MemoryMarshal.Cast<,>()
访问现有内存,将Span<Foo>
改成Span<Vector<Foo>>
;在 string
的情况下,您可能必须使用 ushort
而不是 char
来说服它知道它在做什么(char
和 ushort
在记忆方面是一样的),所以:
var charSpan = someString.AsSpan();
var vectorized = MemoryMarshal.Cast<char, Vector<ushort>>(charSpan);
现在您可以使用 foreach(var v in vectorized)
等访问内存 非常便宜 。要记住的是,最后可能有一些无法放入向量的剩余部分,因此请确保检查这些位;那将是从偏移 vectorized.Length * Vector<ushort>.Count
开始的任何东西。