以下是相关程序的摘录.矩阵img[][]的大小为SIZE×SIZE,并在以下位置初始化:
img[j][i] = 2 * j + i
然后,你创建一个矩阵res[][],这里的每个字段都是img矩阵中它周围9个字段的平均值.为简单起见,边框保留为0.
for(i=1;i<SIZE-1;i++)
for(j=1;j<SIZE-1;j++) {
res[j][i]=0;
for(k=-1;k<2;k++)
for(l=-1;l<2;l++)
res[j][i] += img[j+l][i+k];
res[j][i] /= 9;
}
Run Code Online (Sandbox Code Playgroud)
这就是该计划的全部内容.为了完整起见,以下是之前的内容.没有代码.如您所见,它只是初始化.
#define SIZE 8192
float img[SIZE][SIZE]; // input image
float res[SIZE][SIZE]; //result of mean filter
int i,j,k,l;
for(i=0;i<SIZE;i++)
for(j=0;j<SIZE;j++)
img[j][i] = (2*j+i)%8196;
Run Code Online (Sandbox Code Playgroud)
基本上,当SIZE是2048的倍数时,此程序很慢,例如执行时间:
SIZE = 8191: 3.44 secs
SIZE = 8192: 7.20 secs
SIZE = 8193: 3.18 secs
Run Code Online (Sandbox Code Playgroud)
编译器是GCC.据我所知,这是因为内存管理,但我对这个主题并不太了解,这就是我在这里问的原因.
另外如何解决这个问题会很好,但如果有人能够解释这些执行时间,我已经足够开心了.
我已经知道malloc/free了,但问题不在于使用的内存量,它只是执行时间,所以我不知道这会有多大帮助.
在对不同尺寸的方形矩阵进行一些实验后,出现了一种模式.转换一个大小的矩阵2^n2^n+1总是比转换一个大小的矩阵慢.对于较小的值n,差异并不重要.
然而,在512的值上会出现很大的差异.(至少对我而言)
免责声明:我知道由于元素的双重交换,函数实际上并没有转置矩阵,但它没有任何区别.
遵循代码:
#define SAMPLES 1000
#define MATSIZE 512
#include <time.h>
#include <iostream>
int mat[MATSIZE][MATSIZE];
void transpose()
{
for ( int i = 0 ; i < MATSIZE ; i++ )
for ( int j = 0 ; j < MATSIZE ; j++ )
{
int aux = mat[i][j];
mat[i][j] = mat[j][i];
mat[j][i] = aux;
}
}
int main()
{
//initialize matrix
for ( int i = 0 ; …Run Code Online (Sandbox Code Playgroud) 该内部函数导说,只有这么多关于void _mm_prefetch (char const* p, int i):
从包含地址p的内存中获取数据行到由locality hint i指定的缓存层次结构中的位置.
你能列出int i参数的可能值并解释它们的含义吗?
我发现_MM_HINT_T0,_MM_HINT_T1,_MM_HINT_T2,_MM_HINT_NTA和_MM_HINT_ENTA,但我不知道这是否是一个详尽的列表和它们的含义.
如果特定于处理器,我想知道他们在Ryzen和最新的英特尔酷睿处理器上做了什么.
我已经了解了不同的缓存映射技术,如直接映射,关联映射和集合关联映射技术,还学习了权衡.但我很好奇现在在intel core i7或AMD处理器中使用了什么.以及这些技术是如何演变的.还有哪些事情需要改进?
我一直认为并且知道,由于更好的局部性和节省空间,仅通过乘法完成一次索引的多维数组比通过两个指针取消引用完成索引的数组数组更快。
前一段时间我做了一个小测试,结果很令人惊讶。至少我的 callgrind 分析器报告说使用数组数组的相同函数运行速度稍快一些。
我想知道是否应该更改矩阵类的定义以在内部使用数组数组。这个类几乎在我的模拟引擎中随处使用(?不太确定如何调用..),我确实想找到节省几秒钟的最佳方法。
test_matrix成本为350 200 020,test_array_array成本为325 200 016。-O3该代码由编译clang++。所有成员函数都是根据探查器内联的。
#include <iostream>
#include <memory>
template<class T>
class BasicArray : public std::unique_ptr<T[]> {
public:
BasicArray() = default;
BasicArray(std::size_t);
};
template<class T>
BasicArray<T>::BasicArray(std::size_t size)
: std::unique_ptr<T[]>(new T[size]) {}
template<class T>
class Matrix : public BasicArray<T> {
public:
Matrix() = default;
Matrix(std::size_t, std::size_t);
T &operator()(std::size_t, std::size_t) const;
std::size_t get_index(std::size_t, std::size_t) const;
std::size_t get_size(std::size_t) const;
private:
std::size_t sizes[2];
};
template<class T>
Matrix<T>::Matrix(std::size_t i, …Run Code Online (Sandbox Code Playgroud) Write-Combine缓冲区是如何物理连接的?我已经看到了说明许多变体的方框图:
它是依赖于微架构的吗?
阅读何时应该使用预取?中接受的答案后 以及预取示例中的示例?,我在理解何时实际使用预取方面仍然存在很多问题。虽然这些答案提供了预取很有用的示例,但它们没有解释如何在实际程序中发现它。看起来像是随机猜测。
我特别对 intel x86 的 C 实现(prefetchnta、prefetcht2、prefetcht1、prefetcht0、prefetchw)感兴趣,这些实现可以通过 GCC 的__builtin_prefetch内在函数访问。我想知道:
perf。在这种情况下,什么指标(或它们之间的关系)表明有机会通过软件预取来提高性能?for (int i = 0; i < n; i++) {
// some code
double x = a[i];
// some code
}
Run Code Online (Sandbox Code Playgroud)
我应该在加载之前还是之后放置预取a[i]?它应该指向前方多远a[i+m]?我是否需要担心展开循环以确保我仅在缓存行边界上预取,或者它几乎是免费的,就像nop数据已经在缓存中一样?是否值得__builtin_prefetch连续使用多个调用来一次预取多个缓存行?
struct complex {double real = 0.0; double imag = 0.0;};我有以 3 阶张量形式组织的类型的复杂值数据。底层容器具有与内存页边界对齐的连续内存布局。
张量的自然“切片”方向是沿着方向 1。这意味着缓存行按方向 3、2 和最后 1 的顺序延伸。换句话说,索引函数如下所示:(i, j, k) -> i * N2 * N3 + j * N3 + k。

我需要沿方向 2 转置切片。在上面的第一张图像中,红色矩形是我希望转置的张量的切片。
我的 C++ 代码如下所示:
for (auto vslice_counter = std::size_t{}; vslice_counter < n2; ++vslice_counter)
{
// blocked loop
for (auto bi1 = std::size_t{}; bi1 < n1; bi1 += block_size)
{
for (auto bi3 = std::size_t{}; bi3 < n3; bi3 += block_size)
{
for (auto …Run Code Online (Sandbox Code Playgroud) 这个问题是此处发布的问题的衍生问题:Measurement Bandwidth on a ccNUMA system
我为配备 2 个 Intel(R) Xeon(R) Platinum 8168 的 ccNUMA 系统上的内存带宽编写了一个微基准测试:
作为参考,我使用 Intel Advisor 的屋顶线图,它描述了每个可用 CPU 数据路径的带宽。据此计算,带宽为230GB/s。
问题:如果您查看强扩展图,您可以看到峰值有效带宽实际上是在 33 个 CPU 上实现的,之后添加 CPU 只会降低峰值有效带宽。为什么会发生这种情况?
我有一个循环,我正在尝试与 OpenMP 有效地并行化。它涉及累积矢量流的 L2 范数,并进行缩减。这是循环:
struct vec3
{
float data[3] = {};
};
float accumulate_eta_sq_t_mass(const vec3* etas, const float* masses, const std::size_t& n)
{
auto a = 0.0;
#pragma omp parallel for simd safelen(16) reduction(+:a)
for (auto ii = std::size_t{}; ii < n; ++ii)
{
const auto& eta = etas[ii];
const auto x = static_cast<double>(eta.data[0]);
const auto y = static_cast<double>(eta.data[1]);
const auto z = static_cast<double>(eta.data[2]);
const auto m = static_cast<double>(masses[ii]);
a += (x * x + y * y + …Run Code Online (Sandbox Code Playgroud) c++ benchmarking openmp performance-testing parallelism-amdahl
鉴于 CPU 现在是多核的并且有自己的 L1/L2 缓存,我很好奇 L3 缓存是如何组织的,因为它由多个内核共享。我会想象,如果我们有 4 个内核,那么 L3 缓存将包含 4 个页面的数据,每个页面对应于特定内核引用的内存区域。假设我有点正确,就这样吗?例如,它可以将这些页面中的每一个划分为子页面。这样,当多个线程在同一个内核上运行时,每个线程都可以在其中一个子页面中找到它们的数据。我只是突然想到了这个,所以我非常有兴趣让自己了解幕后真正发生的事情。任何人都可以分享他们的见解或为我提供一个链接来治愈我的无知吗?
提前谢谢了。
c++ ×6
performance ×6
cpu-cache ×4
intel ×4
x86 ×3
prefetch ×2
amd ×1
arrays ×1
benchmarking ×1
c ×1
caching ×1
cpu ×1
gcc ×1
intrinsics ×1
numa ×1
openmp ×1
optimization ×1
profiling ×1
transpose ×1
x86-64 ×1