IQMath定點數運算庫效能測試

Yanye發表於2024-04-03

基本資訊

微控制器:GD32F303RC,執行主頻:120MHz,SRAM:48KB,Flash:256KB
編譯環境:ARMCC 5.06 update6 (build750)

由於iq數的底層資料型別是4位元組的int32_t因此_iq30 ~ _iq1 儘管表示的精度不同,但是運算速度是相同的。下列測試使用_iq15作為被測資料型別,能表示的範圍從-65536到65535.999969483,精度是0.000030518/LSB。

測試程式碼

宣告陣列變數用於儲存兩個運算元向量和一個結果向量

#define CONST_PI_VAL 3.1415926f

#define VECTOR_SIZE  1000

static _iq15 ResultVector[VECTOR_SIZE];
static _iq15 VectorA[VECTOR_SIZE];
static _iq15 VectorB[VECTOR_SIZE];

static float ResultVectorF[VECTOR_SIZE];
static float VectorAF[VECTOR_SIZE];
static float VectorBF[VECTOR_SIZE];

測試陣列的初始化,_IQ15(1.0221f)這種IQ立即數在編譯時就已確定,因此VectorA[index] = _IQ15(1.0221f) * index; 等效於兩個32位資料相乘,陣列初始化不計入測試時間。

static void BenchmarkVectorIQArrayInit(void) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        VectorA[index] = _IQ15(1.0221f) * index;
        VectorB[index] = _IQ15(2.127f) * index;
        ResultVector[index] = 0;
    }
}

static void BenchmarkVectorFloatArrayInit(void) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        VectorAF[index] = 1.0221f * index;
        VectorBF[index] = 2.127f * index;
        ResultVectorF[index] = 0.0f;
    }
}

IQ數累加和浮點數累加

static void VectorIQAdd(_iq15 *vectorA, _iq15 *vectorB, _iq15 *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = vectorA[index]+ vectorB[index];
    }
}

static void VectorFloatAdd(float *vectorA, float *vectorB, float *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = vectorA[index] + vectorB[index];
    }
}

IQ數相乘和浮點數相乘

static void VectorIQMultiply(_iq15 *vectorA, _iq15 *vectorB, _iq15 *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = _IQ15mpy(vectorA[index], vectorB[index]);
    }
}

static void VectorFloatMultiply(float *vectorA, float *vectorB, float *result ) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++){
        result[index] = vectorA[index] * vectorB[index];
    }
}

IQ數除法和浮點數除法

static void VectorIQDiv(_iq15 *vectorA, _iq15 *vectorB, _iq15 *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = _IQ15div(vectorA[index], vectorB[index]);
    }
}

static void VectorFloatDiv(float *vectorA, float *vectorB, float *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = vectorA[index] / vectorB[index];
    }
}

IQ數乘加和浮點數乘加,y=kx+b

static void VectorIQScale(_iq15 *vectorA, _iq15 *vectorB, _iq15 *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = _IQ15mpy(vectorA[index], _IQ15(CONST_PI_VAL));
        result[index] += vectorB[index];
    }
}

static void VectorFloatScale(float *vectorA, float *vectorB, float *result) {
    unsigned int index = 0u;
    for(index = 0; index < VECTOR_SIZE; index++) {
        result[index] = (vectorA[index] * CONST_PI_VAL) + vectorB[index];
    }
}

效能測試使用Cortex-m4自帶的32位DWT計數器,計數頻率和CPU主頻相同。

static void hw_dwt_init(void) {
    // DWT timer enable
    CoreDebug->DEMCR = 0x1000000;
    // clear Cycle Count Register
    DWT->CYCCNT = 0x0;
    // enable  Data Watchpoint and Trace Register
    DWT->CTRL = 0x1;
}

測試程式碼模板,由於測試程式碼執行時間較短,不用考慮DWT計數器溢位問題。

    start = DWT->CYCCNT;
    // 此處執行測試程式碼
    end = DWT->CYCCNT;
    diff = end - start;
    rt_kprintf("elapse:%d\n", diff);

測試結果

IQ數和單精度軟浮點數對比,微控制器未開啟FPU,程式碼最佳化等級-O3,計算次數1000。
image
image
image

DWT計數原始資料:120MHz

資料型別 加法 乘法 除法 乘加
iq15 11006 41007 155487 49006
軟浮點 64454 57436 240989 116753

DWT換算時間:微秒

資料型別 加法 乘法 除法 乘加
iq15 91.716 341.725 1295.725 408.383
軟浮點 537.116 478.633 2008.2416 972.9416

IQ數和單精度硬浮點數對比,微控制器開啟單精度FPU,程式碼最佳化等級-O3,計算次數1000。
image
image
image

DWT計數原始資料:120MHz

資料型別 加法 乘法 除法 乘加
iq15 11006 41007 155454 49006
硬浮點 17007 17007 30007 19039

DWT換算時間:微秒

資料型別 加法 乘法 除法 乘加
iq15 91.716 341.725 1,295.45 408.383
硬浮點 141.725 141.725 250.0583 158.6583

總結

IQ數相比軟浮點數效能提升

加法 乘法 除法 乘加
提升百分比 82.92% 28.604% 35.47% 58.02%

IQ數相比硬浮點數效能提升(下降)

加法 乘法 除法 乘加
提升/下降百分比 35.28% -58.52% -80.697% -61.149%

在微控制器有浮點數加速單元的情況下,開啟浮點數協處理器CP10,並且開啟編譯器的硬浮點程式碼生成,乘法和除法直接使用float資料型別進行計算的速度是最快的;而IQ定點數只在加法和減法有優勢,因此結合兩者使用能帶來最大的效能提升。(IQ定點數可以和浮點數相互轉換)

在沒有FPU的微控制器,例如不帶FPU的Cortex-M4,Cortex-M0,ARM9等核心,使用IQMathlib提供的定點數替代軟浮點數會帶來效能的提升。

即使是精心最佳化的軟體程式碼也難以敵過硬體加速器帶來的效能提升,有浮點數運算需求儘量選擇帶FPU的微控制器。

相關文章