最近需要给远场降噪库编译到android 平台上运行,其中库加载了模型资源文件,考虑到库的通用性,给模型资源文件转成了c的头文件里的数组形式,这样就不需要读取文件了,如下

llama模型加载_llama模型加载

编译后在机器上运行64位版本ok,一切正常,但编译32位版本时遇到bus error

llama模型加载_llama模型加载_02

总线错误?没干啥啊,给32位编译FLAGS 同步成64位后无效,Bus error继续。
查了下总的来说android 报bus error 基本是访问了未对齐内存导致,比如
0x0x5594bb4a7f 这个地址%4不等于0,说明地址不是4字节对齐。如果用int * 去取数据就会报错,但
用char* 取数据就ok。为啥64位的正常呢,打印了64位的数据也是不对齐的,为啥64位就ok呢,猜测是64位支持内存不对齐的访问。

用工具排查错误是在下面这行,那看来就是f32有问题了

llama模型加载_c语言_03


看下f32 是个float * 地址,那应该需要4字节对齐

llama模型加载_Android_04


我们打印下f32的值0x0x5594bb4a7f 果然不是4字节对齐的

怎么办呢,

尝试了下memcpy处理,重新定义一个float 数组,编译器会确保iweightAll 是对齐4字节的,memcpy又可以按字节访问f32

llama模型加载_语音识别_05

再来打印iweightAll 果然ok了,但又有其他地方报错了,。。。看来这种方式治标不治本,的确可以解决问题,但需要在所有不对齐的地方使用,同时增加了memcpy的开销

看一下为什么f32是单字节,能否设置4字节对齐

llama模型加载_语音识别_06


一顿操作发现,f32是用模型资源取出来的char*赋值的。。。我去,那这肯定很难保证是4字节对齐啊

于是想到新的一招

llama模型加载_c语言_07


重新申请个4的倍数的内存,这样会确保ptr 起始地址是4字节对齐的,给原来的值拷贝进去,ok

搞定了想想还是有问题啊,这样内存变大了啊

到底是啥原因导致ptr不能4字节对齐呢,能否有办法搞定呢

原先以为是模型解析的时候,模型里的数据类型不确定,可能是void* 也可能是float*等等,导致赋值的时候有问题,可后来想想模型的制定应该没这么蠢吧,so继续追踪下去,打印所有解析的模型资源数据,发现都是4字节倍数,那这很明显了啊,只要模型资源起始地址对齐的,那我们需要解析的数据肯定都是对齐的,打印了下模型资源地址果然是像0x0x5594bb4a7f 这样的,对,就是不对齐,为啥呢,再看下模型资源

llama模型加载_Android_08


资源的里的数组大小不是4倍数啊。。。打印这个地址果然出来的地址也不是对齐4的(也是有可能对齐的),那对于这种直接定义的数组数据怎么让起始地址对齐呢,想到个简单的解决方法,那就是再扩充几个字节(注意资源长度还是原来的)

llama模型加载_Android_09


再次打印资源地址,ok了,重新编译代码运行,搞定