- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在努力优化我的 Julia 代码并使其运行得更快。
我抽象了我的整个代码的一部分,我希望你评估是否存在一些瓶颈,使过程比优化的过程慢。
代码的简要说明:
array1
n x n 数组,用 randn
随机条目初始化array1
将在循环中的某个算法下更新,直到array1
的所有条目将大于 -0.8
using Random;
function Test()
n=5
sqn = n^2
foo1 = circshift(collect(1:n)', (0, 1))
foo2 = circshift(collect(1:n)', (0, -1))
foo3 = circshift(collect(1:n), 1)
foo4 = circshift(collect(1:n), -1)
# initialize array1 with random entries
array1 = randn(n,n);
# initialize array2 with zeros
array2 = zeros(n,n);
#println(array1);
loop = 0
while minimum(array1) < -0.8 && loop < 100000
loop += 1
bar = zeros(n, n)
# Use simd?
for i = 1:sqn
bar[i] = max(0, array1[i] - 0.2)
end
array2 += bar
adding = zeros(n, n)
# Use simd?
for i = 1:n
for j = 1:n
adding[i, j] =
(1 / 4) * sum([
bar[i, foo1[j]],
bar[i, foo2[j]],
bar[foo3[i], j],
bar[foo4[i], j],
])
end
end
array1 = array1 - bar + adding
end
# println(array1)
# println(array2)
# println(loop)
end
Test()
我想我可以使用
@simd
来节省时间在一些
for statement
.
SIMD
以外的任何有用信息,我会很高兴听到它。
最佳答案
是的,尤其是使用 LoopVectorization.jl -- 尽管还有一些其他优化我们必须先做,然后才能进入球场,这是限制因素。
首先,使用 BenchmarkTools.jl 在我的系统(一台旧笔记本电脑)上的代码的一些初始计时
julia> using BenchmarkTools
julia> @benchmark Test()
BechmarkTools.Trial: 31 samples with 1 evaluations.
Range (min … max): 5.987 μs … 257.525 ms ┊ GC (min … max): 0.00% … 22.07%
Time (median): 234.396 ms ┊ GC (median): 16.67%
Time (mean ± σ): 162.310 ms ± 114.023 ms ┊ GC (mean ± σ): 18.44% ± 8.84%
█ ▂
█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▅▅█▅██▁▃ ▁
5.99 μs Histogram: frequency by time 258 ms <
Memory estimate: 9.84 KiB, allocs estimate: 70.
循环仅在几十次评估中短路的情况与运行完整 100000 次的情况之间似乎存在一些明显的双峰性。顺便说一句,这是一个典型的例子,说明为什么尽管有一些传统智慧,最小次数不是一个很好的基准测试指标,意味着或(甚至更好)完整直方图要好得多——所以来自
BenchmarkTools.jl 的直方图或
BenchmarkHistograms.jl很棒。
function test()
n=5
sqn = n^2
r = collect(1:n)
foo1 = circshift(r', (0, 1))
foo2 = circshift(r', (0, -1))
foo3 = circshift(r, 1)
foo4 = circshift(r, -1)
# initialize array1 with random entries
array1 = randn(n,n);
# initialize array2 with zeros
array2 = zeros(n,n);
# Initialize temporary arrays used in loops
bar = zeros(n, n)
adding = zeros(n, n)
loop = 0
while minimum(array1) < -0.8 && loop < 100000
loop += 1
fill!(bar, 0)
# Use simd?
@inbounds for i = 1:sqn
bar[i] = max(0, array1[i] - 0.2)
end
@. array2 += bar
fill!(adding, 0)
# Use simd?
@inbounds for i = 1:n
for j = 1:n
s = bar[i, foo1[j]] + bar[i, foo2[j]] + bar[foo3[i], j] + bar[foo4[i], j]
adding[i, j] = 0.25 * s
end
end
@. array1 = array1 - bar + adding
end
return array1, array2, loop
end
如您所见,我移动了
bar
的分配。和
adding
在循环之外——因为它们不会改变大小,我们可以只分配它们一次,然后在必要时重新填充零。另一个更改涉及在添加和减去数组时不必要的分配分配。原版
array1 = array1 - bar + adding
例如正在分配,但
@. array1 = array1 - bar + adding
,这只是
array1 .= array1 .- bar .+ adding
的便捷简写, 明确表示我们需要逐元素操作,并将确保它们都就地发生(即,不会触发新的堆分配)。我也放了一个
@inbounds
在
for
循环并稍微重构最内层循环中的求和(虽然
sum
很快,但不是如评论中所述,分配一个全新的数组以在循环的每次迭代中相加)。
julia> @benchmark test()
BechmarkTools.Trial: 305 samples with 1 evaluations.
Range (min … max): 1.622 μs … 30.093 ms ┊ GC (min … max): 0.00% … 0.00%
Time (median): 22.438 ms ┊ GC (median): 0.00%
Time (mean ± σ): 16.429 ms ± 11.530 ms ┊ GC (mean ± σ): 0.00% ± 0.00%
█ ▁
█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁█▇▄▃▃▄▃▅▅▂▃▃▂▃▂ ▂
1.62 μs Histogram: frequency by time 29.4 ms <
Memory estimate: 1.75 KiB, allocs estimate: 9.
现在是 SIMD。原来只是加上
@inbounds @simd
在 for 循环前面没有出现在启用 Julia 编译器尚未找到的任何优化的计时中。
LoopVectorization的
@turbo
但是:
using Random, LoopVectorization
function test_simd_turbo()
n=5
sqn = n^2
r = collect(1:n)
foo1 = circshift(r', (0, 1))
foo2 = circshift(r', (0, -1))
foo3 = circshift(r, 1)
foo4 = circshift(r, -1)
# initialize array1 with random entries
array1 = randn(n,n);
# initialize array2 with zeros
array2 = zeros(n,n);
# Initialize temporary arrays used in loops
bar = zeros(n, n)
adding = zeros(n, n)
loop = 0
while minimum(array1) < -0.8 && loop < 100000
loop += 1
fill!(bar, 0)
# Use simd?
@turbo for i = 1:sqn
bar[i] = max(0, array1[i] - 0.2)
end
@turbo @. array2 += bar
fill!(adding, 0)
# Use simd?
@turbo for i = 1:n
for j = 1:n
s = bar[i, foo1[j]] + bar[i, foo2[j]] + bar[foo3[i], j] + bar[foo4[i], j]
adding[i, j] = 0.25 * s
end
end
@turbo @. array1 = array1 - bar + adding
end
return array1, array2, loop
end
请注意,您可以使用
@turbo
对两者进行 SIMD 向量化
for
循环和
@.
广播,如这里所见。
julia> @benchmark test_simd_turbo()
BechmarkTools.Trial: 419 samples with 1 evaluations.
Range (min … max): 1.864 μs … 28.059 ms ┊ GC (min … max): 0.00% … 0.00%
Time (median): 15.486 ms ┊ GC (median): 0.00%
Time (mean ± σ): 11.946 ms ± 8.034 ms ┊ GC (mean ± σ): 0.00% ± 0.00%
█
█▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▇▇▆▅▄▄▃▄▄▄▃▃▂▁▂▁▁▁▂▁▁▁▁▁▁▃ ▂
1.86 μs Histogram: frequency by time 26.3 ms <
Memory estimate: 1.75 KiB, allocs estimate: 9.
LoopVectorization.jl 的优势在具有
AVX512 的系统上可能会更大。矢量寄存器(我在这台笔记本电脑上只有 AVX2)。
关于arrays - Julia 代码优化 : is this the time to use SIMD?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67857312/
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 想改进这个问题?将问题更新为 on-topic对于堆栈溢出。 7年前关闭。 Improve this qu
我有一个代码库,我可以在我的 mac 上编译和运行,但不能在我的远程 linux 机器上编译和运行,我不确定为什么。 编译时出现错误 fatal error: simd/simd.h: No such
我需要了解如何编写一些可并行化问题的 C++ 跨平台实现,以便在可用的情况下利用 SIMD(SSE、SPU 等)。以及我希望能够在运行时在 SIMD 和非 SIMD 之间切换。 您建议我如何解决这个问
我正在使用 AVX 内在 _mm256_extract_epi32() . 不过,我不完全确定我是否正确使用它,因为 gcc 不喜欢我的代码,而 clang 编译它并运行它没有问题。 我根据整数变量的
当我可以使用 SSE3 或 AVX 时,SSE2 或 MMX 等较旧的 SSE 版本是否可用 - 还是我还需要单独检查它们? 最佳答案 一般来说,这些都是附加的,但请记住,多年来英特尔和 AMD 对这
在 godbolt.org 使用 gcc 7.2 我可以看到以下内容 code在汇编程序中翻译得非常好。我看到 1 次加载、1 次添加和 1 次存储。 #include __attribute__(
假设我们有一个函数将两个数组相乘,每个数组有 1000000 个 double 值。在 C/C++ 中,该函数如下所示: void mul_c(double* a, double* b) {
我有一个 A = a1 a2 a3 a4 b1 b2 b3 b4 c1 c2 c3 c4 d1 d2 d3 d4 我有两排, float32x2_t a = a1 a2 flo
我正在考虑编写一个 SIMD vector 数学库,因此作为一个快速基准,我编写了一个程序,该程序执行 1 亿(4 个 float ) vector 元素乘法并将它们加到累积总数中。对于我的经典非 S
我正在开发带有英特尔编译器 OpenMP 4.0 的英特尔 E5(6 核、12 线程) 为什么这段代码 SIMD 编译比并行 SIMD 编译更快? for (int suppv = 0; suppv
OpenMP 4.0 引入了 SIMD 结构以利用 CPU 的 SIMD 指令。根据规范http://www.openmp.org/mp-documents/OpenMP4.0.0.pdf ,有两种结
英特尔编译器允许我们通过以下方式对循环进行矢量化 #pragma simd for ( ... ) 但是,您也可以选择使用 OpenMP 4 的指令执行此操作: #pragma omp simd fo
关注我的 x86 question ,我想知道如何在 Arm-v8 上有效地矢量化以下代码: static inline uint64_t Compress8x7bit(uint64_t x) {
Intel 提供了几个 SIMD 命令,它们似乎都对 128 位数据执行按位异或: _mm_xor_pd(__m128d, __m128d) _mm_xor_ps(__m128, __m128) _m
可以使用“位打包”技术压缩无符号整数:在一个无符号整数 block 中,只存储有效位,当一个 block 中的所有整数都“小”时,会导致数据压缩。该方法称为 FOR (引用框架)。 有SIMD lib
SSE 寄存器是否在逻辑处理器(超线程)之间共享或复制? 对于 SSE 繁重的程序,我能否期望从并行化中获得与普通程序相同的加速(英特尔声称具有超线程的处理器为 30%)? 最佳答案 从英特尔的文档中
我正在编写一个使用 SSE 指令来乘法和相加整数值的程序。我用浮点数做了同样的程序,但我的整数版本缺少一个指令。 使用浮点数,在完成所有操作后,我将 de 值返回到常规浮点数数组,执行以下操作: _m
我正在开发基于Intel指令集(AVX,FMA等)的高性能算法。当数据按顺序存储时,我的算法(内核)运行良好。但是,现在我面临一个大问题,但没有找到解决方法或解决方案: see 2D Matrix i
大家好 :) 我正在尝试了解有关浮点、SIMD/数学内在函数和 gcc 的快速数学标志的一些概念。更具体地说,我在 x86 cpu 上使用 MinGW 和 gcc v4.5.0。 我已经搜索了一段时间
根据https://sourceware.org/glibc/wiki/libmvec GCC 具有数学函数的向量实现。它们可以被编译器用于优化,可以在这个例子中看到:https://godbolt.
我是一名优秀的程序员,十分优秀!