• NEON优化1:软件性能优化、降功耗怎么搞?


    NEON优化1:软件性能优化、硬件降功耗怎么搞?

    背景


    为了移动端或嵌入式设备等场景也能用上前沿技术,产品往往会上一些复杂的算法模型,但由于算法开销过大,导致实时性差、功耗高等问题,需要进行端侧的性能优化。

    如何在不改变算法效果的前提下,降低算法代码的时间复杂度,成了许多工程师不得不面对的问题。

    性能优化基础之MCPS和MIPS


    首先,在进行性能优化前,应找到一个具体的性能衡量指标,即MIPS/MCPS。

    • MIPS:million instructions per second,程序运行时每秒所耗费的指令数
    • MCPS:million instructions per second,程序运行时每秒所耗费的周期数

    MIPS和MCPS的区别

    • MIPS是指令数,不同平台软仿和硬仿的差距不大
    • MCPS是周期数,由于有硬件优化,可能不同平台会出现MCPS不同,甚至比MIPS还小。

    一般软仿结果,MIPS都比MCPS小,因为软仿工具RVDS的CPI最小才能为1,硬仿结果能直接获得MCPS数。硬仿时,好的CPU能做到CPI小于1,即1个周期多指令,具体见:link

    With a single-execution-unit processor, the best CPI attainable is 1. However, with a multiple-execution-unit processor, one may achieve even better CPI values (CPI < 1).

    MIPS计算DEMO

    目录结构:

    • src
      • main.c
        • void test(int* arr, int len);
      • vpu.h
      • vpu.s

    计算代码:

    #include <stdio.h>
    
    #define MIPS_COUNT_ARM_CORTEX
    
    #ifdef MIPS_COUNT_ARM_CORTEX
    #include "v7_pmu.h"
    #endif
    
    #ifdef MIPS_COUNT_ARM_CORTEX
    #define MILLION_UNIT        (1000000.f)
    #define KILO_UNIT           (1000.f)
    #define FRAME_LEN_MS        (10.f)     // 10ms
    #define COUNT_NUM           1000
    unsigned int counter0;
    unsigned int cycle_count1;
    unsigned int cycle_count2;
    unsigned int cur_time = 0;
    long double cur_time_tmp = 0.0;
    double avg_time = 0; 
    unsigned long avg_time_tmp = 0;
    unsigned int peak_time = 0;
    float cycle2mips_coef = (1 / MILLION_UNIT) / (FRAME_LEN_MS / KILO_UNIT);  // unit: mips
    #endif
    
    
    void main(void) {
        // set mannual
        cnt = COUNT_NUM;
    
        while(cnt--) {
    #ifdef MIPS_COUNT_ARM_CORTEX
            enable_pmu();                // Enable the PMU
            reset_ccnt();                // Reset the CCNT (cycle counter)
            reset_pmn();                 // Reset the configurable counters
            pmn_config(0, 0x03);         // Configure counter 0 to count event code 0x03
            enable_ccnt();               // Enable CCNT
            enable_pmn(0);               // Enable counter
            counter0 = read_pmn(0);      // Read counter 0
            cycle_count1 = read_ccnt();  // Read Core cycle
    #endif
    
            // test();
    
    #ifdef MIPS_COUNT_ARM_CORTEX
            cycle_count2 = read_ccnt();
            cur_time = cycle_count2 - cycle_count1;
            // 10^6 => million cycle, *1000/frmeLms => second
            cur_time_tmp = (float)cur_time * cycle2mips_coef; // mips
            avg_time_tmp += (unsigned int)cur_time_tmp;
            if (cur_time > peak_time) {
                    peak_time = cur_time;
            }
            printf("%.2f mips \n", cur_time_tmp);
    #endif
        }
    
    #ifdef MIPS_COUNT_ARM_CORTEX
        avg_time = (double)avg_time_tmp / COUNT_NUM;
        printf("max %.2f mips \n", (float)peak_time * cycle2mips_coef);
        printf("avg %.2f mips \n", avg_time);
    #endif
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    计算开销的模块函数通常放到要测试开销的相关函数如test()前后,即可得到该函数的单独MIPS开销,当然,也可以根据总体程序运行的开销乘相关函数所占开销比例得到,但计算不便,这里不推荐。

    测试工具及流程


    所需工具

    软仿测试工具通常采用ARM公司的RVDS(RealView Development Suite)开发套件,模拟各种内核处理进行仿真,得到开销数据。

    硬仿测试工具通常是用Andriod平台自带的simpleperf工具,将可执行文件直接推到手机上运行,实时抓取CPU数据得到实际开销数据,并绘制出图,俗称火焰图。

    软硬仿优化流程

    • 软仿流程
      • 安装RVDS软件
      • 配置代码工程环境
      • 跑通代码
      • 编写开销计算代码
      • 仿真Profile
      • 得到热点函数和开销基线
      • 进行代码优化
      • 测试热点函数开销
    • 硬仿流程
      • 与软仿流程类似
      • 建议先软仿,再硬仿
      • 涉及到IO读写等开销问题,软仿无法模拟实际运行情况,以硬仿结果为准

    有了热点开销函数,就可以进行相关指令集及代码优化了。

    小结


    本文分享了性能优化的背景及基础概念,时间复杂度计算之MCPS和MIPS,以及测试工具和软硬仿流程。下篇分享NEON优化的案例与经验。

  • 相关阅读:
    LeetCode 刷题系列 -- 47. 全排列 II
    JS 获取一个对象的 key 值和 value 值
    「学习笔记」线段树标记永久化
    Metabase学习教程:视图-5
    钙尔奇30周年以行动,力挺中国骨骼健康发展
    c语言的内存使用
    二极管如何工作?
    多线程面试相关知识点
    vue 或 js 使用谷歌翻译实现国际化
    Gralloc ION DMABUF in Camera & Display
  • 原文地址:https://blog.csdn.net/qq_17256689/article/details/125308629