-golang和c带有Simd指令

问题描述 投票:0回答:1

我是Golang的新手,我正在对Golang和Cgo进行一些实验。我想看看Golang是否可以通过在简单测试上使用

SIMD
操作的C程序中受益,但是我看到的是,正常的通道比使用CGO从Golang调用的SIMD优化的C代码更快。我听说使用Golang的C处罚,但找不到任何详细信息。这是我的样本,所以任何建议都会有所帮助。

-Golang- CGO测试:

包装cutils

/* #cgo CFLAGS: -mavx2 -Wall -O0 #include <stdio.h> #include <immintrin.h> const char* foo(void) { return __FILE__; } #define FLOATS_IN_AVX_REG 8 void simdAdd(float* out, float* a, float* b, unsigned long len) { const unsigned long vectSize = (len / FLOATS_IN_AVX_REG) * FLOATS_IN_AVX_REG ; unsigned long i=0; for(i=0; i < vectSize; i += FLOATS_IN_AVX_REG) { __m256 regA = _mm256_loadu_ps(a+i); __m256 regB = _mm256_loadu_ps(b+i); __m256 res = _mm256_add_ps(regA, regB); _mm256_storeu_ps(out+i, res); } for(; i < len; i++) { out[i] = a[i] + b[i]; } } */ import "C" import ( "fmt" "unsafe" ) func NoSimdAdd(a, b []float32, l uint32) []float32 { res := make([]float32, l) for i := 0; i < len(a); i++ { res[i] = a[i] + b[i] } return res } func SIMDadd(a, b []float32, l uint32) []float32 { res := make([]float32, l) C.simdAdd( (*C.float)(unsafe.Pointer(&res[0])), (*C.float)(unsafe.Pointer(&a[0])), (*C.float)(unsafe.Pointer(&b[0])), C.ulong(l)) return res }
主要测试:

package main import ( "ex1/files/cutils" "fmt" "math/rand/v2" "time" ) func genFArray(s uint32) []float32 { r := make([]float32, s) for i := range s { r[i] = 1.0 * rand.Float32() * (10.0 - 1.0) } return r } const ( TEST_SIZE = 16 LOOP_CNT = 1000000 ) func main() { a := genFArray(1 << TEST_SIZE) start := time.Now() for i := 0; i < LOOP_CNT; i++ { cutils.SIMDadd(a, a, 1<<TEST_SIZE) } fmt.Printf("SIMD %.2fs elapsed\n", time.Since(start).Seconds()) }
在这里证明SIMD优化的原始C程序也在这里:

#include <stdio.h> #include <immintrin.h> #include <math.h> #include <sys/time.h> // for gettimeofday() #define FLOATS_IN_AVX_REG 8 #define ARR_SIZE (1 << 16) #define LOOP_CNT 1000000 void plain_add(float* out, float* a, float* b, unsigned long len); void simd_add(float* out, float* a, float* b, unsigned long len) ; float func_Uniform(float) ; int main(void) { unsigned long i,j; float arr1[ARR_SIZE]; float result[ARR_SIZE]; for(i=0; i < ARR_SIZE; i++) arr1[i] = func_Uniform(1.0); printf("Start test\r\n"); struct timeval t1, t2; double elapsedTime; gettimeofday(&t1, NULL); for(j=0; j < LOOP_CNT; j++) simd_add(result, arr1, arr1, ARR_SIZE); gettimeofday(&t2, NULL); elapsedTime = (t2.tv_sec - t1.tv_sec) * 1000.0; // sec to ms elapsedTime += (t2.tv_usec - t1.tv_usec) / 1000.0; // us to ms printf("Time elapsed %f ms.\n", elapsedTime); return 0; } float func_Uniform(float a) { return ((float)rand()/(float)(RAND_MAX)) * a ; } void plain_add(float* out, float* a, float* b, unsigned long len) { unsigned long i; for(i=0; i < len; i++) out[i] = a[i] + b[i]; } void simd_add(float* out, float* a, float* b, unsigned long len) { const unsigned long vectSize = (len / FLOATS_IN_AVX_REG) * FLOATS_IN_AVX_REG ; unsigned long i=0; for(i=0; i < vectSize; i += FLOATS_IN_AVX_REG) { __m256 regA = _mm256_loadu_ps(a+i); __m256 regB = _mm256_loadu_ps(b+i); __m256 res = _mm256_add_ps(regA, regB); _mm256_storeu_ps(out+i, res); } for(; i < len; i++) { out[i] = a[i] + b[i]; } }
因此,使用SIMD对NO SIMD测试的C程序具有明显的差异:

no simd Start test Time elapsed 206796.292000 ms. simd Start test Time elapsed 84095.521000 ms.
然而,Golang实验的差异各不相同,但SIMD较慢。
thanks.

[编辑]:我已经更改了测试,看到了一些改进,而且还没有使用

go run .

我构建了二进制文件,以便能够使用所有代码静态链接,并希望获得最好的链接。我还将循环计数传递给C,因为更改C代码为:

void simdAddTest(float* out, float* a, float* b, unsigned long len, unsigned long loopcnt) {
    unsigned long l ;
    for(l=0; l  < loopcnt; l++) {
        simdAdd(out, a, b, len);
    }
}

仅一次从Golang打电话:
func SIMDAdd2(a, b []float32, l uint32, cnt uint32) []float32 {
    res := make([]float32, l)
    C.simdAddTest(
        (*C.float)(unsafe.Pointer(&res[0])),
        (*C.float)(unsafe.Pointer(&a[0])),
        (*C.float)(unsafe.Pointer(&b[0])),
        C.ulong(l),
        C.ulong(cnt))
    return res
}

现在结果更合理:
NO SIMD 59.71s elapsed
SIMD 41.10s elapsed

IT在SIMD和NON SIMD矢量添加之间的差异约为10-15秒,这是某种程度上的,但是我也不确定这是我可以从中挤出的最好的。

我在使用CGO从GO调用C函数时会看到额外的开销,这会产生性能问题。即使您在C.

中使用SIMD,也可能会减慢速度。 trory通过CGO与GO的本机性能比较普通C函数(无SIMD)的性能,以查看高架CGO增加了多少。另外,请确保您使用的是-O3之类的编译器优化,并且对于Simd。

此外,您也可以尝试并行化工作或寻找直接使用SIMD的GO库,避免CGO,以防CGO开销仍然是问题。
go simd cgo
1个回答
0
投票

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.