{"id":459188,"date":"2025-05-11T21:00:15","date_gmt":"2025-05-11T21:00:15","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=459188"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=459188","title":{"rendered":"<span>\u0420\u0435\u0448\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u0441 Route 256 \u043d\u0430 goalng<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u00ab<strong>\u0413\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b<\/strong>\u00bb \u0441\u00a0\u043a\u043e\u043d\u0442\u0435\u0441\u0442\u0430 Route 256\u00a0\u043e\u0442\u00a0Ozon.<\/p>\n<p>\u0421\u0441\u044b\u043b\u043e\u0447\u043a\u0438:<br \/><a href=\"https:\/\/habr.com\/ru\/articles\/720582\/\" rel=\"noopener noreferrer nofollow\">Assembler \u0432 Go: \u0442\u0435\u0445\u043d\u0438\u043a\u0438 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \/ \u0425\u0430\u0431\u0440<\/a> <br \/><a href=\"https:\/\/habr.com\/ru\/companies\/vk\/articles\/358088\/\" rel=\"noopener noreferrer nofollow\">\u0420\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e \u0430\u0441\u0441\u0435\u043c\u0431\u043b\u0435\u0440\u0443 Go \/ \u0425\u0430\u0431\u0440<\/a> <br \/><a href=\"https:\/\/habr.com\/ru\/companies\/oleg-bunin\/articles\/905966\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 1. \u041f\u043e\u0447\u0435\u043c\u0443 Go-\u0430\u0441\u0441\u0435\u043c\u0431\u043b\u0435\u0440 \u0438 \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u044b: \u0438\u0434\u0435\u044f \u0434\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \/ \u0425\u0430\u0431\u0440<\/a>  <\/p>\n<h2>\u0423\u0441\u043b\u043e\u0432\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438<\/h2>\n<p>\u0413\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u043e\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0430\u0441\u0441\u0438\u0432, \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u044b\u0441\u043e\u0442\u0443 \u0441\u0442\u043e\u043b\u0431\u0438\u043a\u0430 \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438. \u0414\u0432\u0435 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u043c\u0438, \u0435\u0441\u043b\u0438 \u043f\u0440\u0438 \u0441\u043e\u0432\u043c\u0435\u0449\u0435\u043d\u0438\u0438 \u043e\u0434\u043d\u043e\u0439 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u043e\u0439, \u043f\u043e\u0432\u0451\u0440\u043d\u0443\u0442\u043e\u0439 \u043d\u0430 \u0443\u0433\u043e\u043b 180\u00b0, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0440\u043e\u0432\u043d\u044b\u0439 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a \u0431\u0435\u0437 \u043d\u0430\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u043e\u0432.  <\/p>\n<p><strong>\u0418\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u044f  <\/strong><\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b54\/c66\/129\/b54c661292d9ebadd9dcfaaf3624e0fb.png\" width=\"926\" height=\"704\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/b54\/c66\/129\/b54c661292d9ebadd9dcfaaf3624e0fb.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b54\/c66\/129\/b54c661292d9ebadd9dcfaaf3624e0fb.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440 \u0442\u0435\u0441\u0442\u0430<\/h4>\n<p>1 2 4 <br \/>1 3 4 <br \/>1 4 3  <\/p>\n<p><strong>\u041e\u0442\u0432\u0435\u0442:<\/strong>  1 \u043f\u0430\u0440\u0430<\/p>\n<p><strong>\u0422\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435:<\/strong><\/p>\n<pre><code class=\"go\">func profile(a []uint32) string { n := len(a) res := make([]uint32, n-1) for i := 1; i &lt; n; i++ { res[i-1] = a[i] - a[i-1] }  b := unsafe.Slice((*byte)(unsafe.Pointer(&amp;res[0])), (n-1)*4) return *(*string)(unsafe.Pointer(&amp;b)) }  func reverseProfile(a []uint32) string { n := len(a) res := make([]uint32, n-1) for i := n - 1; i &gt; 0; i-- { res[n-1-i] = a[i] - a[i-1] }  b := unsafe.Slice((*byte)(unsafe.Pointer(&amp;res[0])), (n-1)*4) return *(*string)(unsafe.Pointer(&amp;b)) }  func processHistograms(histos [][]uint32) int { profCount := make(map[string]int) for i := 0; i &lt; len(histos); i++ { p := profile(histos[i]) profCount[p]++ }  res := 0 for i := 0; i &lt; len(histos); i++ { rp := reverseProfile(histos[i]) res += profCount[rp] \/\/ \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u0438 \u0440\u0435\u0432\u0435\u0440\u0441 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442, \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u0430\u0440\u0443 (a,a) if profile(histos[i]) == rp { res-- } } return res \/ 2 }<\/code><\/pre>\n<p>\u041c\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043f\u0440\u0438\u0440\u043e\u0441\u0442\u044b \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c \u0438 \u043d\u0430\u0445\u043e\u0434\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u0430\u0440\u044b, \u043f\u0440\u0438\u0440\u043e\u0441\u0442\u044b \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442. \u041d\u0438\u0447\u0435\u0433\u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e.<\/p>\n<p>\u042d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0442\u0435\u0441\u0442\u044b \u0441 \u043a\u043e\u043d\u0442\u0435\u0441\u0442\u0430, \u043d\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SIMD.<\/p>\n<p><strong>\u0423\u0441\u043a\u043e\u0440\u0438\u0442\u044c <\/strong><code><strong>func profile <\/strong><\/code><strong>\u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e.<\/strong><\/p>\n<pre><code class=\"erlang\">\/\/ func calcDifferences(src []int32, dst []int32) \/\/ \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u044b \u043e\u0442 GPT-4.1 TEXT \u00b7calcDifferences(SB), $0-48     MOVQ src_base+0(FP),    SI  \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0430\u0434\u0440\u0435\u0441 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430     MOVQ src_len+8(FP),     CX  \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0434\u043b\u0438\u043d\u0443 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430     MOVQ dst_base+24(FP),   DI  \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0430\u0434\u0440\u0435\u0441 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f          CMPQ CX, $1                 \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0435\u0441\u043b\u0438 \u0434\u043b\u0438\u043d\u0430 &lt;= 1     JLE  done                   \/\/ \u0415\u0441\u043b\u0438 \u0434\u0430, \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443          DECQ CX                     \/\/ \u0414\u043b\u0438\u043d\u0430 dst = \u0434\u043b\u0438\u043d\u0430 src - 1     XORQ AX, AX                 \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0438\u043d\u0434\u0435\u043a\u0441\u0430 \u043d\u0443\u043b\u0435\u043c      \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f AVX \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u043c\u0438\u043d\u0438\u043c\u0443\u043c 8)     CMPQ CX, $8     JL   scalar_loop            \/\/ \u0415\u0441\u043b\u0438 \u043c\u0435\u043d\u044c\u0448\u0435 8, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435      \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f AVX \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u043a\u0440\u0430\u0442\u043d\u043e 8)     MOVQ CX, DX     ANDQ $-8, DX                \/\/ \u041e\u043a\u0440\u0443\u0433\u043b\u044f\u0435\u043c \u0432\u043d\u0438\u0437 \u0434\u043e \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0433\u043e \u043a\u0440\u0430\u0442\u043d\u043e\u0433\u043e 8  avx_loop:     VMOVDQU (SI)(AX*4), Y0      \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u0437 src \u0432 YMM0     VMOVDQU 4(SI)(AX*4), Y1     \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 (\u0441\u043e \u0441\u0434\u0432\u0438\u0433\u043e\u043c +1)     VPSUBD Y0, Y1, Y2           \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u044b (Y1 - Y0)     VMOVDQU Y2, (DI)(AX*4)      \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c 8 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0432 dst          ADDQ $8, AX                 \/\/ \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0434\u0435\u043a\u0441 \u043d\u0430 8     CMPQ AX, DX                 \/\/ \u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0441 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432     JL   avx_loop               \/\/ \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0446\u0438\u043a\u043b, \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f AVX \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438      \/\/ \u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0435\u0441\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u043e     CMPQ AX, CX     JGE  done                   \/\/ \u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u044b, \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c  scalar_loop:     MOVL (SI)(AX*4), BX         \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c src[i] \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440 BX     MOVL 4(SI)(AX*4), DX        \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c src[i+1] \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440 DX     SUBL BX, DX                 \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u0443: DX = src[i+1] - src[i]     MOVL DX, (DI)(AX*4)         \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 dst[i]          INCQ AX                     \/\/ \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0434\u0435\u043a\u0441     CMPQ AX, CX                 \/\/ \u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0441 \u0434\u043b\u0438\u043d\u043e\u0439 \u043c\u0430\u0441\u0441\u0438\u0432\u0430     JL   scalar_loop            \/\/ \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c, \u0435\u0441\u043b\u0438 \u0438\u043d\u0434\u0435\u043a\u0441 &lt; \u0434\u043b\u0438\u043d\u044b  done:     RET                         \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0442 \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <\/code><\/pre>\n<pre><code class=\"go\">\/\/ \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 Go \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 func CalcDifferencesGo(arr []uint32) []uint32 { if len(arr) &lt;= 1 { return []uint32{} }  result := make([]uint32, len(arr)-1) for i := 0; i &lt; len(arr)-1; i++ { result[i] = arr[i+1] - arr[i] } return result }  \/\/go:noescape func calcDifferences(src []uint32, dst []uint32)  \/\/ CalculateGrowth - \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 SIMD func CalcDifferencesASM(arr []uint32) []uint32 { if len(arr) &lt;= 1 { return []uint32{} }  if len(arr) &lt;= 4 { return CalcDifferencesGo(arr) }  result := make([]uint32, len(arr)-1) calcDifferences(arr, result) return result }<\/code><\/pre>\n<p><strong>\u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/strong><\/p>\n<p>\u041c\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440 Y0 \u0432\u043e\u0441\u0435\u043c\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u043e 32 \u0431\u0438\u0442\u0430, \u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440 Y1 \u0441\u043e \u0441\u043c\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u043d\u0430 \u043e\u0434\u0438\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442. \u041f\u043e\u043b\u0443\u0447\u0438\u0432 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u0443\u044e \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u043c\u0438, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043f\u0440\u0438\u0440\u043e\u0441\u0442\u0430 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c \u0441\u0440\u0430\u0437\u0443. <\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0c4\/e30\/f4b\/0c4e30f4bc72b8bb9283ec85b1a94fd6.png\" width=\"1531\" height=\"521\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/0c4\/e30\/f4b\/0c4e30f4bc72b8bb9283ec85b1a94fd6.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0c4\/e30\/f4b\/0c4e30f4bc72b8bb9283ec85b1a94fd6.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u00ab\u0425\u0432\u043e\u0441\u0442\u00bb \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0432\u043e\u0439\u0434\u0443\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0432 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u043e.<\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0434\u043b\u044f \u0434\u043b\u0438\u043d \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c \u043e\u0442 10 \u0434\u043e 100000<br \/>\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u0432 ~2 \u0440\u0430\u0437\u0430 (\u0430 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0432 4~8)<\/p>\n<pre><code class=\"erlang\">goos: windows goarch: amd64 pkg: qwe cpu: AMD Ryzen 5 8400F 6-Core Processor Benchmark_profile\/Go-10-12               67875990                19.03 ns\/op Benchmark_profile\/SIMD-10-12             66618182                18.76 ns\/op Benchmark_profile\/Go-100-12              13702243                92.77 ns\/op Benchmark_profile\/SIMD-100-12            15909126                77.92 ns\/op Benchmark_profile\/Go-1000-12              1294166                954.4 ns\/op Benchmark_profile\/SIMD-1000-12            1835912                636.4 ns\/op Benchmark_profile\/Go-10000-12              144406                 7867 ns\/op Benchmark_profile\/SIMD-10000-12            277306                 4469 ns\/op Benchmark_profile\/Go-100000-12              19545                63121 ns\/op Benchmark_profile\/SIMD-100000-12            43426                28094 ns\/op<\/code><\/pre>\n<p><strong>\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 <\/strong><code><strong>func reverseProfile<\/strong><\/code><strong> \u0447\u0443\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u0435\u0435<\/strong><\/p>\n<p>\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u0432\u044b\u0447\u0438\u0442\u0430\u043d\u0438\u0435, \u043d\u043e \u0438 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0432\u0435\u043a\u0442\u043e\u0440\u0435.<\/p>\n<pre><code class=\"erlang\">\/\/ func calcReverseDifferences(src []int32, dst []int32) \/\/ \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u044b \u043e\u0442 GPT-4.1 TEXT \u00b7calcReverseDifferences(SB), $0-48     MOVQ src_base+0(FP), SI     \/\/ SI = &amp;src[0]     MOVQ src_len+8(FP), CX      \/\/ CX = len(src)     MOVQ dst_base+24(FP), DI    \/\/ DI = &amp;dst[0]          CMPQ CX, $1                 \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0434\u043b\u0438\u043d\u0443     JLE  done          DECQ CX                     \/\/ CX = len(dst) = len(src)-1     MOVQ CX, AX                 \/\/ AX \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u043c \u0432 dst (\u0438\u0434\u0435\u043c \u0441 \u043a\u043e\u043d\u0446\u0430)     XORQ DX, DX                 \/\/ DX = \u0438\u043d\u0434\u0435\u043a\u0441 \u0432 src (\u0438\u0434\u0435\u043c \u0441 \u043d\u0430\u0447\u0430\u043b\u0430)      \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f AVX     CMPQ CX, $8     JL   scalar_loop_start      \/\/ AVX-\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 (\u0431\u043b\u043e\u043a\u0430\u043c\u0438 \u043f\u043e 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432)     MOVQ CX, R8     ANDQ $-8, R8                \/\/ R8 = \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u0440\u0430\u0442\u043d\u044b\u0445 8     MOVQ R8, R9                 \/\/ R9 = \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432  avx_loop:     \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0435 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432     VMOVDQU (SI)(DX*4), Y0      \/\/ Y0 = src[DX..DX+7]     \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 (\u0441\u0434\u0432\u0438\u0433 \u043d\u0430 1)     VMOVDQU 4(SI)(DX*4), Y1     \/\/ Y1 = src[DX+1..DX+8]          \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u044b     VPSUBD Y0, Y1, Y2           \/\/ Y2 = \u0440\u0430\u0437\u043d\u0438\u0446\u044b          \/\/ \u0420\u0435\u0432\u0435\u0440\u0441\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432     VPERM2I128 $0x01, Y2, Y2, Y3  \/\/ \u041c\u0435\u043d\u044f\u0435\u043c \u043c\u0435\u0441\u0442\u0430\u043c\u0438 128-\u0431\u0438\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u044b     VPSHUFD $0x1B, Y3, Y3       \/\/ \u0420\u0435\u0432\u0435\u0440\u0441\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0435          \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435     MOVQ AX, R10     SUBQ $8, R10                \/\/ R10 = AX-7 (\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438)     VMOVDQU Y3, (DI)(R10*4)     \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432          ADDQ $8, DX                 \/\/ \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u0441\u0447\u0435\u0442\u0447\u0438\u043a src     SUBQ $8, AX                 \/\/ \u0423\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u043c \u0441\u0447\u0435\u0442\u0447\u0438\u043a dst     CMPQ DX, R8                 \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 AVX-\u0446\u0438\u043a\u043b\u0430     JL   avx_loop  scalar_loop_start:     DECQ AX scalar_loop:     CMPQ DX, CX                 \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435     JGE  done          MOVL (SI)(DX*4), BX         \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c src[i]     MOVL 4(SI)(DX*4), BP        \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c src[i+1]     SUBL BX, BP                 \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u0443     MOVL BP, (DI)(AX*4)         \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432 dst          INCQ DX                     \/\/ \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 src     DECQ AX                     \/\/ \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f dst     JMP  scalar_loop  done:     RET <\/code><\/pre>\n<pre><code class=\"go\">\/\/ \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 Go \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 func CalcReverseDifferencesGo(arr []uint32) []uint32 { if len(arr) &lt;= 1 { return []uint32{} }  result := make([]uint32, len(arr)-1) for i := len(arr) - 1; i &gt; 0; i-- { result[len(arr)-1-i] = arr[i] - arr[i-1] } return result }  \/\/go:noescape func calcReverseDifferences(src []uint32, dst []uint32)  \/\/ CalculateGrowth - \u043e\u0431\u0435\u0440\u0442\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f func CalReversecDifferencesASM(arr []uint32) []uint32 { if len(arr) &lt;= 1 { return []uint32{} }  if len(arr) &lt;= 4 { return CalcReverseDifferencesGo(arr) }  result := make([]uint32, len(arr)-1) calcReverseDifferences(arr, result) return result }<\/code><\/pre>\n<p>\u0412\u0441\u0435 \u0442\u0430\u043a\u0436\u0435 \u043a\u0430\u043a \u0438 \u0441 <code>calcDifferences <\/code>\u043d\u043e \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u043c\u0438<\/p>\n<p><strong>VPERM2I128 $0x01, Y2, Y2, Y3<\/strong>  <\/p>\n<p>\u042d\u0442\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u0431\u0435\u0440\u0435\u0442 \u0434\u0432\u0430 256-\u0431\u0438\u0442\u043d\u044b\u0445 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 (\u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0431\u0430 \u2014 Y2) \u0438 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0445 128-\u0431\u0438\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u044b.<\/p>\n<p><strong>VPSHUFD $0x1B, Y3, Y3<\/strong>  <\/p>\n<p>\u042d\u0442\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 32-\u0431\u0438\u0442\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u0439 128-\u0431\u0438\u0442\u043d\u043e\u0439 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 Y3.<\/p>\n<p><strong>\u0418\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/strong><\/p>\n<figure class=\"full-width\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a3f\/4bc\/995\/a3f4bc995a2e9760461252372277df01.png\" width=\"681\" height=\"429\" sizes=\"auto, (max-width: 780px) 100vw, 50vw\" srcset=\"https:\/\/habrastorage.org\/r\/w780\/getpro\/habr\/upload_files\/a3f\/4bc\/995\/a3f4bc995a2e9760461252372277df01.png 780w,&#10;       https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a3f\/4bc\/995\/a3f4bc995a2e9760461252372277df01.png 781w\" loading=\"lazy\" decode=\"async\"\/><\/figure>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b <code>calcDifferences <\/code><\/p>\n<pre><code class=\"erlang\">goos: windows goarch: amd64 pkg: qwe cpu: AMD Ryzen 5 8400F 6-Core Processor Benchmark_reverse_profile\/Go-10-12                57465208             20.66 ns\/op Benchmark_reverse_profile\/ASM-10-12               61966186             19.28 ns\/op Benchmark_reverse_profile\/Go-100-12               11149742             107.8 ns\/op Benchmark_reverse_profile\/ASM-100-12              15162312             76.59 ns\/op Benchmark_reverse_profile\/Go-1000-12               1000000              1022 ns\/op Benchmark_reverse_profile\/ASM-1000-12              1756675             679.6 ns\/op Benchmark_reverse_profile\/Go-10000-12               129410              9519 ns\/op Benchmark_reverse_profile\/ASM-10000-12              208200              4928 ns\/op Benchmark_reverse_profile\/Go-100000-12               15706             76804 ns\/op Benchmark_reverse_profile\/ASM-100000-12              38287             30263 ns\/op<\/code><\/pre>\n<p>\u0418\u0442\u043e\u0433\u043e \u0441\u043e\u0432\u043e\u043a\u0443\u043f\u043d\u044b\u0439 \u043f\u0440\u0438\u0440\u043e\u0441\u0442 \u0434\u043b\u044f \u043d\u0430\u0431\u043e\u0440\u0430 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c \u0441 200000 \u043f\u0430\u0440\u0430\u043c\u0438 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u043b <\/p>\n<p>2.80 \u0440\u0430\u0437\u0430 (180.07% \u0431\u044b\u0441\u0442\u0440\u0435\u0435)<\/p>\n<pre><code class=\"go\">func TestHistogramProcessing(t *testing.T) { \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0433\u0435\u043d\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0445 \u0447\u0438\u0441\u0435\u043b seed := time.Now().UnixNano() rand.Seed(seed) t.Logf(\"\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c seed: %d\", seed)  const lengthHistograms = 10_000 const numHistograms = 10_000 const numPair = 20 const numRandom = 10000  var Histogram [][]uint32  for i := 0; i &lt; numHistograms; i++ { qwe, asd := generatePairedHistograms(lengthHistograms, numPair) Histogram = append(Histogram, asd...) Histogram = append(Histogram, qwe) }  \/\/ \u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0445 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c for i := 0; i &lt; numRandom; i++ { Histogram = append(Histogram, generateRandomHistogram(lengthHistograms)) }  \/\/ \u0417\u0430\u043c\u0435\u0440 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0434\u043b\u044f processHistograms start1 := time.Now() result1Paired := processHistograms(Histogram) duration1 := time.Since(start1)  \/\/ \u0417\u0430\u043c\u0435\u0440 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0434\u043b\u044f processHistogramsAVX start2 := time.Now() result2Paired := processHistogramsAVX(Histogram) duration2 := time.Since(start2)  if result1Paired != result2Paired { t.Errorf(\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0434\u043b\u044f \u043f\u0430\u0440\u043d\u044b\u0445 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c \u043d\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442: processHistograms=%d, processHistogramsAVX=%d\", result1Paired, result2Paired) } else { fmt.Printf(\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0434\u043b\u044f \u043f\u0430\u0440\u043d\u044b\u0445 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442: %d \\n\", result1Paired) t.Logf(\"\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0434\u043b\u044f \u043f\u0430\u0440\u043d\u044b\u0445 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442: %d\", result1Paired) }  \/\/ \u0412\u044b\u0432\u043e\u0434\u0438\u043c \u0437\u0430\u043c\u0435\u0440\u044b \u0432\u0440\u0435\u043c\u0435\u043d\u0438 t.Logf(\"\u0412\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f processHistograms: %v\", duration1) t.Logf(\"\u0412\u0440\u0435\u043c\u044f \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f processHistogramsAVX: %v\", duration2)  \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0432\u043e \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437 \u043e\u0434\u043d\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0434\u0440\u0443\u0433\u043e\u0439 var faster, slower time.Duration var fasterName, slowerName string if duration1 &lt; duration2 { faster, slower = duration1, duration2 fasterName, slowerName = \"processHistograms\", \"processHistogramsAVX\" } else { faster, slower = duration2, duration1 fasterName, slowerName = \"processHistogramsAVX\", \"processHistograms\" }  speedup := float64(slower) \/ float64(faster) percentDiff := (speedup - 1) * 100  t.Logf(\"%s \u0431\u044b\u0441\u0442\u0440\u0435\u0435 %s \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0432 %.2f \u0440\u0430\u0437\u0430 (%.2f%% \u0431\u044b\u0441\u0442\u0440\u0435\u0435)\", fasterName, slowerName, speedup, percentDiff)  fmt.Printf(\"%s \u0431\u044b\u0441\u0442\u0440\u0435\u0435 %s \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0432 %.2f \u0440\u0430\u0437\u0430 (%.2f%% \u0431\u044b\u0441\u0442\u0440\u0435\u0435)\\n\", fasterName, slowerName, speedup, percentDiff) }<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/908384\/\"> https:\/\/habr.com\/ru\/articles\/908384\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438 \u00ab<strong>\u0413\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b<\/strong>\u00bb \u0441\u00a0\u043a\u043e\u043d\u0442\u0435\u0441\u0442\u0430 Route 256\u00a0\u043e\u0442\u00a0Ozon.<\/p>\n<p>\u0421\u0441\u044b\u043b\u043e\u0447\u043a\u0438:<br \/><a href=\"https:\/\/habr.com\/ru\/articles\/720582\/\" rel=\"noopener noreferrer nofollow\">Assembler \u0432 Go: \u0442\u0435\u0445\u043d\u0438\u043a\u0438 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0438 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \/ \u0425\u0430\u0431\u0440<\/a> <br \/><a href=\"https:\/\/habr.com\/ru\/companies\/vk\/articles\/358088\/\" rel=\"noopener noreferrer nofollow\">\u0420\u0443\u043a\u043e\u0432\u043e\u0434\u0441\u0442\u0432\u043e \u043f\u043e \u0430\u0441\u0441\u0435\u043c\u0431\u043b\u0435\u0440\u0443 Go \/ \u0425\u0430\u0431\u0440<\/a> <br \/><a href=\"https:\/\/habr.com\/ru\/companies\/oleg-bunin\/articles\/905966\/\" rel=\"noopener noreferrer nofollow\">\u0427\u0430\u0441\u0442\u044c 1. \u041f\u043e\u0447\u0435\u043c\u0443 Go-\u0430\u0441\u0441\u0435\u043c\u0431\u043b\u0435\u0440 \u0438 \u0432\u0435\u043a\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u043b\u0435\u0437\u043d\u044b: \u0438\u0434\u0435\u044f \u0434\u043b\u044f \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \/ \u0425\u0430\u0431\u0440<\/a>  <\/p>\n<h2>\u0423\u0441\u043b\u043e\u0432\u0438\u0435 \u0437\u0430\u0434\u0430\u0447\u0438<\/h2>\n<p>\u0413\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u043e\u0439 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043c\u0430\u0441\u0441\u0438\u0432, \u043a\u0430\u0436\u0434\u044b\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u044b\u0441\u043e\u0442\u0443 \u0441\u0442\u043e\u043b\u0431\u0438\u043a\u0430 \u043d\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u0439 \u043f\u043e\u0437\u0438\u0446\u0438\u0438. \u0414\u0432\u0435 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0441\u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u043c\u0438, \u0435\u0441\u043b\u0438 \u043f\u0440\u0438 \u0441\u043e\u0432\u043c\u0435\u0449\u0435\u043d\u0438\u0438 \u043e\u0434\u043d\u043e\u0439 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u043e\u0439, \u043f\u043e\u0432\u0451\u0440\u043d\u0443\u0442\u043e\u0439 \u043d\u0430 \u0443\u0433\u043e\u043b 180\u00b0, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0440\u043e\u0432\u043d\u044b\u0439 \u043f\u0440\u044f\u043c\u043e\u0443\u0433\u043e\u043b\u044c\u043d\u0438\u043a \u0431\u0435\u0437 \u043d\u0430\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u043e\u0432.  <\/p>\n<p><strong>\u0418\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u044f  <\/strong><\/p>\n<figure class=\"full-width\"><\/figure>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440 \u0442\u0435\u0441\u0442\u0430<\/h4>\n<p>1 2 4 <br \/>1 3 4 <br \/>1 4 3  <\/p>\n<p><strong>\u041e\u0442\u0432\u0435\u0442:<\/strong>  1 \u043f\u0430\u0440\u0430<\/p>\n<p><strong>\u0422\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435:<\/strong><\/p>\n<pre><code class=\"go\">func profile(a []uint32) string { n := len(a) res := make([]uint32, n-1) for i := 1; i &lt; n; i++ { res[i-1] = a[i] - a[i-1] }  b := unsafe.Slice((*byte)(unsafe.Pointer(&amp;res[0])), (n-1)*4) return *(*string)(unsafe.Pointer(&amp;b)) }  func reverseProfile(a []uint32) string { n := len(a) res := make([]uint32, n-1) for i := n - 1; i &gt; 0; i-- { res[n-1-i] = a[i] - a[i-1] }  b := unsafe.Slice((*byte)(unsafe.Pointer(&amp;res[0])), (n-1)*4) return *(*string)(unsafe.Pointer(&amp;b)) }  func processHistograms(histos [][]uint32) int { profCount := make(map[string]int) for i := 0; i &lt; len(histos); i++ { p := profile(histos[i]) profCount[p]++ }  res := 0 for i := 0; i &lt; len(histos); i++ { rp := reverseProfile(histos[i]) res += profCount[rp] \/\/ \u0435\u0441\u043b\u0438 \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u0438 \u0440\u0435\u0432\u0435\u0440\u0441 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442, \u043d\u0435 \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043f\u0430\u0440\u0443 (a,a) if profile(histos[i]) == rp { res-- } } return res \/ 2 }<\/code><\/pre>\n<p>\u041c\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043f\u0440\u0438\u0440\u043e\u0441\u0442\u044b \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c \u0438 \u043d\u0430\u0445\u043e\u0434\u0438 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u0430\u0440\u044b, \u043f\u0440\u0438\u0440\u043e\u0441\u0442\u044b \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043e\u0432\u043f\u0430\u0434\u0430\u044e\u0442. \u041d\u0438\u0447\u0435\u0433\u043e \u0441\u043b\u043e\u0436\u043d\u043e\u0433\u043e.<\/p>\n<p>\u042d\u0442\u043e \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0442\u0435\u0441\u0442\u044b \u0441 \u043a\u043e\u043d\u0442\u0435\u0441\u0442\u0430, \u043d\u043e \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SIMD.<\/p>\n<p><strong>\u0423\u0441\u043a\u043e\u0440\u0438\u0442\u044c <\/strong><code><strong>func profile <\/strong><\/code><strong>\u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e.<\/strong><\/p>\n<pre><code class=\"erlang\">\/\/ func calcDifferences(src []int32, dst []int32) \/\/ \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u044b \u043e\u0442 GPT-4.1 TEXT \u00b7calcDifferences(SB), $0-48     MOVQ src_base+0(FP),    SI  \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0430\u0434\u0440\u0435\u0441 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430     MOVQ src_len+8(FP),     CX  \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0434\u043b\u0438\u043d\u0443 \u0438\u0441\u0445\u043e\u0434\u043d\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430     MOVQ dst_base+24(FP),   DI  \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0430\u0434\u0440\u0435\u0441 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f          CMPQ CX, $1                 \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0435\u0441\u043b\u0438 \u0434\u043b\u0438\u043d\u0430 &lt;= 1     JLE  done                   \/\/ \u0415\u0441\u043b\u0438 \u0434\u0430, \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c \u0440\u0430\u0431\u043e\u0442\u0443          DECQ CX                     \/\/ \u0414\u043b\u0438\u043d\u0430 dst = \u0434\u043b\u0438\u043d\u0430 src - 1     XORQ AX, AX                 \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u0438\u043d\u0434\u0435\u043a\u0441\u0430 \u043d\u0443\u043b\u0435\u043c      \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f AVX \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u043c\u0438\u043d\u0438\u043c\u0443\u043c 8)     CMPQ CX, $8     JL   scalar_loop            \/\/ \u0415\u0441\u043b\u0438 \u043c\u0435\u043d\u044c\u0448\u0435 8, \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u043c \u043a \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u043e\u0439 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0435      \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f AVX \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 (\u043a\u0440\u0430\u0442\u043d\u043e 8)     MOVQ CX, DX     ANDQ $-8, DX                \/\/ \u041e\u043a\u0440\u0443\u0433\u043b\u044f\u0435\u043c \u0432\u043d\u0438\u0437 \u0434\u043e \u0431\u043b\u0438\u0436\u0430\u0439\u0448\u0435\u0433\u043e \u043a\u0440\u0430\u0442\u043d\u043e\u0433\u043e 8  avx_loop:     VMOVDQU (SI)(AX*4), Y0      \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u0437 src \u0432 YMM0     VMOVDQU 4(SI)(AX*4), Y1     \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 (\u0441\u043e \u0441\u0434\u0432\u0438\u0433\u043e\u043c +1)     VPSUBD Y0, Y1, Y2           \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u044b (Y1 - Y0)     VMOVDQU Y2, (DI)(AX*4)      \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c 8 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432 \u0432 dst          ADDQ $8, AX                 \/\/ \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0434\u0435\u043a\u0441 \u043d\u0430 8     CMPQ AX, DX                 \/\/ \u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0441 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432     JL   avx_loop               \/\/ \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0446\u0438\u043a\u043b, \u0435\u0441\u043b\u0438 \u0435\u0441\u0442\u044c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0434\u043b\u044f AVX \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438      \/\/ \u041e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u043e\u0441\u0442\u0430\u0432\u0448\u0438\u0435\u0441\u044f \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u043e     CMPQ AX, CX     JGE  done                   \/\/ \u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u044b, \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u043c  scalar_loop:     MOVL (SI)(AX*4), BX         \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c src[i] \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440 BX     MOVL 4(SI)(AX*4), DX        \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c src[i+1] \u0432 \u0440\u0435\u0433\u0438\u0441\u0442\u0440 DX     SUBL BX, DX                 \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u0443: DX = src[i+1] - src[i]     MOVL DX, (DI)(AX*4)         \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u0432 dst[i]          INCQ AX                     \/\/ \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0434\u0435\u043a\u0441     CMPQ AX, CX                 \/\/ \u0421\u0440\u0430\u0432\u043d\u0438\u0432\u0430\u0435\u043c \u0441 \u0434\u043b\u0438\u043d\u043e\u0439 \u043c\u0430\u0441\u0441\u0438\u0432\u0430     JL   scalar_loop            \/\/ \u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c, \u0435\u0441\u043b\u0438 \u0438\u043d\u0434\u0435\u043a\u0441 &lt; \u0434\u043b\u0438\u043d\u044b  done:     RET                         \/\/ \u0412\u043e\u0437\u0432\u0440\u0430\u0442 \u0438\u0437 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <\/code><\/pre>\n<pre><code class=\"go\">\/\/ \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 Go \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 func CalcDifferencesGo(arr []uint32) []uint32 { if len(arr) &lt;= 1 { return []uint32{} }  result := make([]uint32, len(arr)-1) for i := 0; i &lt; len(arr)-1; i++ { result[i] = arr[i+1] - arr[i] } return result }  \/\/go:noescape func calcDifferences(src []uint32, dst []uint32)  \/\/ CalculateGrowth - \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 SIMD func CalcDifferencesASM(arr []uint32) []uint32 { if len(arr) &lt;= 1 { return []uint32{} }  if len(arr) &lt;= 4 { return CalcDifferencesGo(arr) }  result := make([]uint32, len(arr)-1) calcDifferences(arr, result) return result }<\/code><\/pre>\n<p><strong>\u041a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442<\/strong><\/p>\n<p>\u041c\u044b \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440 Y0 \u0432\u043e\u0441\u0435\u043c\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u043e 32 \u0431\u0438\u0442\u0430, \u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440 Y1 \u0441\u043e \u0441\u043c\u0435\u0448\u0435\u043d\u0438\u0435\u043c \u043d\u0430 \u043e\u0434\u0438\u043d \u044d\u043b\u0435\u043c\u0435\u043d\u0442. \u041f\u043e\u043b\u0443\u0447\u0438\u0432 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u0443\u044e \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u043c\u0435\u0436\u0434\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u043c\u0438, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u043f\u0440\u0438\u0440\u043e\u0441\u0442\u0430 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c \u0441\u0440\u0430\u0437\u0443. <\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u00ab\u0425\u0432\u043e\u0441\u0442\u00bb \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0432\u043e\u0439\u0434\u0443\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0432 \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u044b\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440, \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c \u0441\u043a\u0430\u043b\u044f\u0440\u043d\u043e.<\/p>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0434\u043b\u044f \u0434\u043b\u0438\u043d \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c \u043e\u0442 10 \u0434\u043e 100000<br \/>\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u0432 ~2 \u0440\u0430\u0437\u0430 (\u0430 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0432 4~8)<\/p>\n<pre><code class=\"erlang\">goos: windows goarch: amd64 pkg: qwe cpu: AMD Ryzen 5 8400F 6-Core Processor Benchmark_profile\/Go-10-12               67875990                19.03 ns\/op Benchmark_profile\/SIMD-10-12             66618182                18.76 ns\/op Benchmark_profile\/Go-100-12              13702243                92.77 ns\/op Benchmark_profile\/SIMD-100-12            15909126                77.92 ns\/op Benchmark_profile\/Go-1000-12              1294166                954.4 ns\/op Benchmark_profile\/SIMD-1000-12            1835912                636.4 ns\/op Benchmark_profile\/Go-10000-12              144406                 7867 ns\/op Benchmark_profile\/SIMD-10000-12            277306                 4469 ns\/op Benchmark_profile\/Go-100000-12              19545                63121 ns\/op Benchmark_profile\/SIMD-100000-12            43426                28094 ns\/op<\/code><\/pre>\n<p><strong>\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 <\/strong><code><strong>func reverseProfile<\/strong><\/code><strong> \u0447\u0443\u0442\u044c \u0441\u043b\u043e\u0436\u043d\u0435\u0435<\/strong><\/p>\n<p>\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0432\u0435\u043a\u0442\u043e\u0440\u043d\u043e\u0435 \u0432\u044b\u0447\u0438\u0442\u0430\u043d\u0438\u0435, \u043d\u043e \u0438 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0432 \u0432\u0435\u043a\u0442\u043e\u0440\u0435.<\/p>\n<pre><code class=\"erlang\">\/\/ func calcReverseDifferences(src []int32, dst []int32) \/\/ \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u044b \u043e\u0442 GPT-4.1 TEXT \u00b7calcReverseDifferences(SB), $0-48     MOVQ src_base+0(FP), SI     \/\/ SI = &amp;src[0]     MOVQ src_len+8(FP), CX      \/\/ CX = len(src)     MOVQ dst_base+24(FP), DI    \/\/ DI = &amp;dst[0]          CMPQ CX, $1                 \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u0443\u044e \u0434\u043b\u0438\u043d\u0443     JLE  done          DECQ CX                     \/\/ CX = len(dst) = len(src)-1     MOVQ CX, AX                 \/\/ AX \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u043c \u0432 dst (\u0438\u0434\u0435\u043c \u0441 \u043a\u043e\u043d\u0446\u0430)     XORQ DX, DX                 \/\/ DX = \u0438\u043d\u0434\u0435\u043a\u0441 \u0432 src (\u0438\u0434\u0435\u043c \u0441 \u043d\u0430\u0447\u0430\u043b\u0430)      \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0438 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0434\u043b\u044f AVX     CMPQ CX, $8     JL   scalar_loop_start      \/\/ AVX-\u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 (\u0431\u043b\u043e\u043a\u0430\u043c\u0438 \u043f\u043e 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432)     MOVQ CX, R8     ANDQ $-8, R8                \/\/ R8 = \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432, \u043a\u0440\u0430\u0442\u043d\u044b\u0445 8     MOVQ R8, R9                 \/\/ R9 = \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0445 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432  avx_loop:     \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0442\u0435\u043a\u0443\u0449\u0438\u0435 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432     VMOVDQU (SI)(DX*4), Y0      \/\/ Y0 = src[DX..DX+7]     \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 (\u0441\u0434\u0432\u0438\u0433 \u043d\u0430 1)     VMOVDQU 4(SI)(DX*4), Y1     \/\/ Y1 = src[DX+1..DX+8]          \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u044b     VPSUBD Y0, Y1, Y2           \/\/ Y2 = \u0440\u0430\u0437\u043d\u0438\u0446\u044b          \/\/ \u0420\u0435\u0432\u0435\u0440\u0441\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432     VPERM2I128 $0x01, Y2, Y2, Y3  \/\/ \u041c\u0435\u043d\u044f\u0435\u043c \u043c\u0435\u0441\u0442\u0430\u043c\u0438 128-\u0431\u0438\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u044b     VPSHUFD $0x1B, Y3, Y3       \/\/ \u0420\u0435\u0432\u0435\u0440\u0441\u0438\u0440\u0443\u0435\u043c \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0432 \u043a\u0430\u0436\u0434\u043e\u0439 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0435          \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432 \u043e\u0431\u0440\u0430\u0442\u043d\u043e\u043c \u043f\u043e\u0440\u044f\u0434\u043a\u0435     MOVQ AX, R10     SUBQ $8, R10                \/\/ R10 = AX-7 (\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0438)     VMOVDQU Y3, (DI)(R10*4)     \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c 8 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432          ADDQ $8, DX                 \/\/ \u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u0441\u0447\u0435\u0442\u0447\u0438\u043a src     SUBQ $8, AX                 \/\/ \u0423\u043c\u0435\u043d\u044c\u0448\u0430\u0435\u043c \u0441\u0447\u0435\u0442\u0447\u0438\u043a dst     CMPQ DX, R8                 \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435 AVX-\u0446\u0438\u043a\u043b\u0430     JL   avx_loop  scalar_loop_start:     DECQ AX scalar_loop:     CMPQ DX, CX                 \/\/ \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u0435     JGE  done          MOVL (SI)(DX*4), BX         \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c src[i]     MOVL 4(SI)(DX*4), BP        \/\/ \u0417\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c src[i+1]     SUBL BX, BP                 \/\/ \u0412\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u0443     MOVL BP, (DI)(AX*4)         \/\/ \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432 dst          INCQ DX                     \/\/ \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 src     DECQ AX                     \/\/ \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u043e\u0437\u0438\u0446\u0438\u044f dst     JMP  scalar_loop  done:     RET <\/code><\/pre>\n<pre><code class=\"go\">\/\/ \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 Go \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 func CalcReverseDifferencesGo(arr []uint32) []uint32 { if len(arr) &lt;= 1 { return []uint32{} }  result := make([]uint32, len(arr)-1) for i := len(arr) - 1; i &gt; 0; i-- { result[len(arr)-1-i] = arr[i] - arr[i-1] } return result }  \/\/go:noescape func calcReverseDifferences(src []uint32, dst []uint32)  \/\/ CalculateGrowth - \u043e\u0431\u0435\u0440\u0442\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0441\u043e\u0437\u0434\u0430\u0435\u0442 \u043c\u0430\u0441\u0441\u0438\u0432 \u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f func CalReversecDifferencesASM(arr []uint32) []uint32 { if len(arr) &lt;= 1 { return []uint32{} }  if len(arr) &lt;= 4 { return CalcReverseDifferencesGo(arr) }  result := make([]uint32, len(arr)-1) calcReverseDifferences(arr, result) return result }<\/code><\/pre>\n<p>\u0412\u0441\u0435 \u0442\u0430\u043a\u0436\u0435 \u043a\u0430\u043a \u0438 \u0441 <code>calcDifferences <\/code>\u043d\u043e \u0434\u0440\u0443\u0433\u043e\u0439 \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0438\u043d\u0434\u0435\u043a\u0441\u0430\u043c\u0438<\/p>\n<p><strong>VPERM2I128 $0x01, Y2, Y2, Y3<\/strong>  <\/p>\n<p>\u042d\u0442\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u0431\u0435\u0440\u0435\u0442 \u0434\u0432\u0430 256-\u0431\u0438\u0442\u043d\u044b\u0445 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 (\u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043e\u0431\u0430 \u2014 Y2) \u0438 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0445 128-\u0431\u0438\u0442\u043d\u044b\u0435 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u044b.<\/p>\n<p><strong>VPSHUFD $0x1B, Y3, Y3<\/strong>  <\/p>\n<p>\u042d\u0442\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 32-\u0431\u0438\u0442\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0432\u043d\u0443\u0442\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u0439 128-\u0431\u0438\u0442\u043d\u043e\u0439 \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 Y3.<\/p>\n<p><strong>\u0418\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/strong><\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u041f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u044b <code>calcDifferences <\/code><\/p>\n<pre><code class=\"erlang\">goos: windows goarch: amd64 pkg: qwe cpu: AMD Ryzen 5 8400F 6-Core Processor Benchmark_reverse_profile\/Go-10-12                57465208             20.66 ns\/op Benchmark_reverse_profile\/ASM-10-12               61966186             19.28 ns\/op Benchmark_reverse_profile\/Go-100-12               11149742             107.8 ns\/op Benchmark_reverse_profile\/ASM-100-12              15162312             76.59 ns\/op Benchmark_reverse_profile\/Go-1000-12               1000000              1022 ns\/op Benchmark_reverse_profile\/ASM-1000-12              1756675             679.6 ns\/op Benchmark_reverse_profile\/Go-10000-12               129410              9519 ns\/op Benchmark_reverse_profile\/ASM-10000-12              208200              4928 ns\/op Benchmark_reverse_profile\/Go-100000-12               15706             76804 ns\/op Benchmark_reverse_profile\/ASM-100000-12<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-459188","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/459188","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=459188"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/459188\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=459188"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=459188"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=459188"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}