相关疑难解决方法(0)

指针数组与元素数组

今天早上我和同事就这个话题进行了讨论.他说,将数组分配为指针数组总是更好,因为分别分配每个元素有更好的机会获得一个空闲的内存块.有人这样想:

// Consider n_elements as a dynamic value
int n_elements = 10, i;
int **ary = (int **) malloc(sizeof(int *) * n_elements);

for(i = 0; i < n_elements; i++)
{
  ary[i] = (int *) malloc(sizeof(int));
}
Run Code Online (Sandbox Code Playgroud)

与他的方法相反,我认为分配元素数组更好,只是因为你会得到一个紧凑的内存块而不是堆在堆中的一堆引用.像这样的东西:

int n_elements = 10;
int *ary = (int *) malloc(sizeof(int) * n_elements);

ary[0] = 100;
Run Code Online (Sandbox Code Playgroud)

在这次谈话之后我一直在思考它,我的最终结论是它取决于它.由于上面提到的原因,我在处理小数据类型时发现第二种解决方案是更好的方法,但是当分配大型结构的数组时,第一种可能更好.

除了我的结论,你怎么看待它?

c arrays pointers memory-management

4
推荐指数
1
解决办法
175
查看次数

_builtin_prefetch() 中第二个参数的作用是什么?

此处的 GCC 文档指定了 _buitin_prefetch 的用法。

第三个论点是完美的。若为0,编译器产生prefetchtnta(%rax)指令 若为1,编译器产生prefetcht2(%rax)指令 若为2,编译器产生prefetcht1(%rax)指令 若为3(默认),编译器产生prefetcht0 (%rax) 指令。

如果我们改变第三个参数,操作码已经相应地改变了。

但是第二个参数似乎没有任何效果。

__builtin_prefetch(&x,1,2);
__builtin_prefetch(&x,0,2);
__builtin_prefetch(&x,0,1);
__builtin_prefetch(&x,0,0);
Run Code Online (Sandbox Code Playgroud)

以上是生成的示例代码:

以下是组装:

 27:    0f 18 10                prefetcht1 (%rax)
  2a:   48 8d 45 fc             lea    -0x4(%rbp),%rax
  2e:   0f 18 10                prefetcht1 (%rax)
  31:   48 8d 45 fc             lea    -0x4(%rbp),%rax
  35:   0f 18 18                prefetcht2 (%rax)
  38:   48 8d 45 fc             lea    -0x4(%rbp),%rax
  3c:   0f 18 00                prefetchnta (%rax)
Run Code Online (Sandbox Code Playgroud)

可以观察到第三个参数的操作码的变化。但即使我更改了第二个参数(指定读或写),汇编代码也保持不变。<27,2a> 和 <2e,31>。所以它不会向机器提供任何信息。那么第二个论点的目的是什么?

c x86 assembly gcc prefetch

4
推荐指数
2
解决办法
1556
查看次数

_mm_prefetch如何工作?

这里所述的_mm_prefetch调用将内容从RAM中的给定存储器位置预取到高速缓存行.但是缓存完全在硬件控制之下吗?基于经常访问的存储器(基于空间/时间位置),硬件将内容从存储器预取到高速缓存.我认为程序员无法控制缓存,它完全是一种硬件机制.

所以我的理解是错误的,缓存实际上可以由我们控制,对吧?

如果_mm_prefetch可以控制什么可以放在缓存中,

  1. 这是否意味着它永远不会从缓存中删除?

  2. 什么是等效的汇编级指令,它适用于缓存机制?

assembly caching sse prefetch visual-studio-2010

4
推荐指数
1
解决办法
1765
查看次数

如何正确使用预取指令?

我试图矢量化循环,计算大浮点矢量的点积.我正在并行计算它,利用CPU拥有大量XMM寄存器的事实,如下所示:

__m128* A, B;
__m128 dot0, dot1, dot2, dot3 = _mm_set_ps1(0);
for(size_t i=0; i<1048576;i+=4) {
    dot0 = _mm_add_ps( dot0, _mm_mul_ps( A[i+0], B[i+0]);
    dot1 = _mm_add_ps( dot1, _mm_mul_ps( A[i+1], B[i+1]);
    dot2 = _mm_add_ps( dot2, _mm_mul_ps( A[i+2], B[i+2]);
    dot3 = _mm_add_ps( dot3, _mm_mul_ps( A[i+3], B[i+3]);
}
... // add dots, then shuffle/hadd result.
Run Code Online (Sandbox Code Playgroud)

我听说使用预取指令可以帮助加速,因为它可以"在后台"获取更多数据,同时执行muls并添加缓存中的数据.但是我没有找到关于如何使用_mm_prefetch()的示例和解释,何时使用什么地址和什么命中.你可以帮忙吗?

x86 caching sse prefetch dot-product

4
推荐指数
1
解决办法
1612
查看次数

物理上靠近 CPU 的内存会比物理上远离 CPU 的内存执行得更快吗?

我知道考虑到计算机的工作速度,这听起来可能是一个愚蠢的问题,但是说 RAM 中的某个地址在物理上更靠近主板上的 CPU,与位于尽可能远离 CPU 的内存地址相比,与最远的内存地址相比,这对访问较近的内存地址的速度有影响吗?

memory cpu performance ram cpu-architecture

3
推荐指数
1
解决办法
420
查看次数

x86_64 CPU是否使用相同的缓存行通过共享内存在2个进程之间进行通信?

众所周知,现代x86_64上的所有缓存L1 / L2 / L3级别都是虚拟索引的,并进行了物理标记。并且所有内核都通过QPI / HyperTransport上的高速缓存一致性协议MOESI / MESIF通过最后一级高速缓存-L3进行通信。

例如,Sandybridge系列CPU具有4至16路高速缓存L3和page_size 4KB,那么这允许在并发进程之间交换数据,并发进程通过共享内存在不同内核上执行。这是可能的,因为高速缓存L3不能同时包含与进程1的页面和与进程2的页面相同的物理内存区域。

这是否意味着每次进程1请求相同的共享内存区域时,进程2会将其页面的缓存行刷新到RAM中,然后进程1加载与页面的缓存行相同的内存区域在process-1的虚拟空间中?真的很慢还是处理器使用了一些优化?

现代的x86_64 CPU是否使用相同的缓存行,而不进行任何刷新,以通过共享内存在具有不同虚拟空间的2个进程之间进行通信?

Sandy Bridge Intel CPU-缓存L3:

  • 8 MB-缓存大小
  • 64 B-缓存行大小
  • 128 K-行(128 K = 8 MB / 64 B)
  • 16路
  • 8 K-路数集(8 K = 128 K线/ 16路)
  • 虚拟地址(索引)的13位[18:6]-定义当前设置号(这是标签)
  • 512 K-每个相同(虚拟地址/ 512 K)竞争同一组(8 MB / 16路)
  • 低19位-对确定当前设置的数字有效

  • 4 KB-标准页面大小

  • 仅低12位-每个地址的虚拟和物理地址相同

我们有7个丢失的位[18:12]-即我们需要检查(7 ^ 2 * 16位)= 1024个缓存行。这与1024路缓存相同-因此非常慢。这是否意味着缓存L3(已物理索引,已物理标记)?

标签虚拟地址中丢失位的摘要(页面大小8 KB-12位):

  • L3(8 MB = 64 B x 128 K线),16路,8 K集,13位标签[18:6]-缺少7位
  • L2(256 KB = 64 B x 4 …

concurrency x86 multithreading x86-64 cpu-cache

2
推荐指数
1
解决办法
581
查看次数

与字节可寻址相比,从字可寻址存储器中获取 4 字节字是否更容易?

所以我确实在 stackvoerflow 中找到了一些与此相关的答案,但没有一个人清楚地回答了这个

因此,如果我们的内存是字节可寻址的,并且字长是例如 4 字节,那么为什么不使内存字节可寻址呢?

如果我没弄错的话,CPU 会用词对吗?因此,当 cpu 尝试从内存中获取一个字时,从字节可寻址内存中获取 4 字节字与从字可寻址内存中获取一个字之间有什么区别?

memory cpu cpu-architecture

2
推荐指数
1
解决办法
802
查看次数

SIMD 2D矩阵英特尔指令集

我正在开发基于Intel指令集(AVX,FMA等)的高性能算法。当数据按顺序存储时,我的算法(内核)运行良好。但是,现在我面临一个大问题,但没有找到解决方法或解决方案: 请参阅2D矩阵

int x, y; x = y = 4096;
float data[x*y]__attribute__((aligned(32)));
float buffer[y]__attribute__((aligned(32)));

/* simple test data */ 
for (i = 0; i < x; i++)
    for (j = 0; j < y; j++)
        data[y*i+j] = y*i+j; // 0,1,2,3...4095, | 4096,4097, ... 8191 |...

/* 1) Extract the columns out of matrix */
__m256i vindex; __m256 vec;
    vindex = _mm256_set_epi32(7*y, 6*y, 5*y, 4*y, 3*y, 2*y, y, 0);


 for(i = 0; i < x; i+=8)
 {
   vec = _mm256_i32gather_ps (&data[i*y], …
Run Code Online (Sandbox Code Playgroud)

c x86 simd matrix avx

2
推荐指数
1
解决办法
358
查看次数

处理器如何读取内存?

我正在尝试重新实现 malloc 并且我需要了解对齐的目的。据我了解,如果内存对齐,代码将执行得更快,因为处理器不必采取额外的步骤来恢复被切割的内存位。我想我明白 64 位处理器读取 64 位 x 64 位内存。现在,让我们假设我有一个按顺序排列的结构(没有填充):一个字符、一个短字符、一个字符和一个整数。为什么短路会错位?我们拥有区块中的所有数据!为什么它必须在一个 2 的倍数的地址上。对于整数和其他类型,同样的问题?

我还有第二个问题:使用我之前提到的结构,处理器如何知道当它读取它的 64 位时前 8 位对应于一个字符,然后接下来的 16 位对应于一个短等等......?

c cpu cpu-architecture memory-alignment low-level

2
推荐指数
1
解决办法
743
查看次数

使用 Numba 对 2 个矩阵求和的最快方法是什么?

我试图找到使用 Numba 对两个相同大小的矩阵求和的最快方法。我想出了 3 种不同的方法,但没有一种能打败 Numpy。这是我的代码:

import numpy as np
from numba import njit,vectorize, prange,float64
import timeit
import time

# function 1: 
def sum_numpy(A,B):
    return A+B

# function 2: 
sum_numba_simple= njit(cache=True,fastmath=True) (sum_numpy)

# function 3: 
@vectorize([float64(float64, float64)])
def sum_numba_vectorized(A,B):
    return A+B

# function 4: 
@njit('(float64[:,:],float64[:,:])', cache=True, fastmath=True, parallel=True)
def sum_numba_loop(A,B):
    n=A.shape[0]
    m=A.shape[1]
    C = np.empty((n, m), A.dtype)

    for i in prange(n):
        for j in prange(m):
            C[i,j]=A[i,j]+B[i,j]
  
    return C

#Test the functions with 2 matrices of size 1,000,000x3:
N=1000000
np.random.seed(123)
A=np.random.uniform(low=-10, …
Run Code Online (Sandbox Code Playgroud)

performance time multithreading numpy numba

2
推荐指数
1
解决办法
349
查看次数