常见问题

ARM CPU 硬件平台编程相关

虽然当前现在通过交叉编译器,为ARM平台编程和X86平台基本是差不多,但是也能发现最根本的区别,就是ARM平台不会自动处理字节对齐,因此有时会引发一些奇特的问题,更有时还会一起一些次生问题: 我们说3个场景:

当我们声明结构体时,需要用pack(1),来避免结构体空洞,这个是为了避免编译器自动4对齐,但是是否会自动4对齐,这个是不确定的。

#pragma pack(push)
#pragma pack(1)

struct ZXM10_DTH_Data_t{
    unsigned int data_id;
    float  temperature;
    float  humid;
    tele_c_time update_time;
};
#pragma pack(pop)

上面这个结构体,每个成员变量的位置都算好了,但是如果结构体声明的时候的首地址不对,也会出问题,此时

__attribute__((__aligned__(4)))  
ZXM10_DTH_Data_t cData;  

就能保证一定4对齐,避免的arm奇怪的错误

对short,int,float的指针的处理,做取值的时候,也需要注意

对于内存地址位置不明的,直接*(float*)有一定概率会得到错误的数值,此时应当使用中间变量过度一下

float fNotOK = *(float*)data;  
float aOK;  
memcpy(&aOK, data, 4);  

此时aOK的值一定是对的

B接口相关

B接口WebService请求报错

现象1: FSU调用SC的B接口时候报错:

Error Message:Unmarshalling Error: unrecognized type name: {http://schemas.xmlsoap.org/soap/encoding/}string. Did you mean {http://www.w3.org/2001/XMLSchema}string?

解决方案:这种一般是SCService的wsdl不匹配造成的,修复需要2个动作: 比如SC的地址是 http://192.168.3.2:8080/services/SCServices
第一步:更新wsdl 进入/opt/www/application/extension/third_part/

wget http://192.168.3.2:8080/services/SCServices?wsdl -O SCService.wsdl 注意请求的url要加wsdl

第二步: 删除wsdl缓存 rm /tmp/wsdl-*

然后再进行B接口测试。

现象2: FSU调用SC的B接口时候报错

Fault occurred while processing

解决方案:通过观察soap调用,发现wsdl请求和soap请求都正常发出,但是参数并没有传递过去,造成服务端报错。暂时先按照"现象1“方法尝试解决。

dropbear ssh无法登录,连接报错:debug1: expecting SSH2_MSG_KEX_ECDH_REPLY

网上说的都不对,如果平时都是好的,偶然一台出现问题,检查FSU上的/etc/dropbear目录是否存在。Dropbear启动的时候会在/etc/dropbear生成自己的指纹,目录不存在导致dropbear直接工作不正常。

SMDDevice 启动过程中崩溃

现象: 一般都是由于SMDDevice,libvdevice.so 和 驱动文件,编译时使用的头文件不匹配造成的。包括一些莫名其妙的问题,工作不正常,但是不崩溃,都有可能是这个原因。

解决方案:将libvdevice.so 和 SMDDevice 更新到最新。 libvdevice.so 一般在 /FsuOS/lib/libvdevice.so SMDDevice 一般在 /FsuOS/SMDDevice

然后将每个分类的驱动目录内的驱动都删除,再看是否可以启动。 /FsuOS/DIPlugins /FsuOS/AIPlugins /FsuOS/SPPlugins /FsuOS/SocketPlugins

再将最新的驱动上传回来。

协议驱动已经配置,但是没有采集到数据

常见原因:

  • 现场接线不对,造成发送的召测命令没有回复,表现为完全没有数据
  • 现场接线短路,造成发送的召测命令,接受到和召测一模一样的数据
  • 通信参数不对,主要为波特率不对,通信地址不对,表现为完全没有数据
  • 通信协议配置不对,和设备不匹配,一般情况表现为完全没有数据
  • 兼容协议和设备不匹配,比如现在最常用的2种协议,modbus和电总,很多设备都支持这2种协议,但是数据地址和命令不同,召测时会发生有的命令回复,有的不回复
  • 协议都对了,还是收不上来数据,主要考虑是逻辑参数配置不对
  • 什么都对了,也有回复,但是数据还是不显示,到此可考虑是协议兼容性不足,需要调试解决不兼容的地方。

为什么感觉到FsuOS相比原系统CPU使用率升高了

我们在实际应用中也观察到这个情况,有多方面的原因:

1 最主要的一个原因,是采集程序工作方式,和操作系统的串口驱动DMA问题。

一般的程序,采用的是 发命令 - 等50-100ms - 接收数据 这种同步阻塞方式,这种一般是小型测试程序使用的技术。 好一点的程序,采用的select的方式, 发命令 - select/poll - 接收哪怕一个字节 - 接着select/poll 这种方式一般被称为reactive被动反应式程序,即根据事件有数据,被动的被通知,然后去读数据到缓存区,然后处理。
FsuOS采用的是proactive主动反应式,即我提前准备好缓存区,然后异步读,操作系统直接把底层收到的数据放到我的缓存区里,然后通知我处理。相对select方式,执行流程明显少了好几个步骤,是目前能用到的最好的网络程序结构,毛病就是异步读写真的很反人类,大家刚开始用的时候脑子很扭曲,程序为什么不是顺着走的。

当在X86上时,由于设备驱动完整性比较高,DMA一般都是工作的,两者工作类似,FsuOS的方式会更省CPU,因为FsuOS没有等待的工作,会立即释放CPU。

当在嵌入式Linux系统上时,由于Linux内核是厂家自己配置的,君光所有FSU的串口驱动都实现了DMA模式,但是观测到的部分厂家的FSU,没有实现DMA模式,此时读取数据的区别就表现出来了。

假设设备回复了50个字节的数据:

  • 当采用第一种方式,由于程序有50-100ms的等待时间而没有发出接收命令,操作系统内部接收会把50个字节都缓存起来,当程序发送接收命令时,一次收到50个字节。
  • 当采用2,3方式时,select会监测有没有数据到达,如果操作系统内部没有DMA,每当到一个字节,select会立即返回并触发接收函数,50个字节,需要重复50次才能接收完毕,此时效率就会大大降低。如果操作系统内部DMA工作正常的话,那么操作系统会根据串口驱动的实现情况,通过DMA一次传送50个字节,或者30个字节+20个字节,1次或者几次就能完成接收,此时程序效率是相当的。

通过对串口数据收发打印就能观察到这类情况。

那么2种方式,哪个是对的? 从程序发展的方向看,select/poll的方式已经是正统道路,preactive更激进,发送-等待-接收只适合小型测试程序使用。select/poll以及在其之上的异步io,在多线程池方式下,会大大提高调度运行效率。并发程度高的程序,对操作系统/程序上下文调用切换,线程锁的使用,都有比较明确的优化方法,并发度越高,留给每个线程的可使用CPU时间越少。而发送-等待-接受,在等待这一步,已经是死路一条,不具备优化空间,只是在小范围的应用中,表现够用而已。

异步程序反人类的事情,这些年伴随高级语言引入的lambda闭包函数,callback回掉函数,大家用着用着也就适应了。

2 PHP性能偏低。我们观察到很多FSU的控制程序用原生C程序实现B接口,这个虽然会带来比较好的性能优势。但是B接口作为WebService,本质是B/S结构的一种,使用C程序实现会造成维护困难。PHP虽然性能相对于原生程序弱一些,但是程序维护和扩展都非常容易,生态也比较统一,对程序员比较友好。 并且我们也实现了B接口的增强模式,大家可以先用PHP程序进行系统的调试,等调试完成后,切换到boost模式,然后B接口的数据处理会由cpp程序处理,就能获得最快的速度。

关于各种语言,开发库等性能的对比

我们在网上经常看到各种语言,各种性能包,自说自话的进行性能对比,我比你性能高, 在一个比较高的配置上:8核i7,16GB内存,256GB固态盘这种系统上,分别运行程序,得出的自己有利的结论,我性能好。
我们在近20年的实际项目中,在硬件性能过剩的情况下,是很难判断出2个语言或者软件实现到底哪个更好一些,因为都能运行,运行的都还不错,实际同一个语言实现的程序对比,代码加个循环性能就大不一样,而我们发现在配置很低的设备上, 性能问题往往一下就现形了,往往以一个可以正常运行,一个压根跑不动结束比赛的。
FsuOS的软件性能优化,最应该感谢都就是那些低配置的FSU设备,首先是303MINI,300MHZ的Arm9搭配64MB内存,直接把我们用了多年的codeigniter框架干报废了,什么thinkphp,‌‌Laravel‌,Symfony‌,yii没有一个能打的,测试了很多改了一个性能比较良好的框架。 EISU的300HMZ的Arm9配64M内存再配2.6.15的Linux内核直接把CPP的代码干的性能不足了,又是一顿优化。低配置的FSU运行顺畅了,高配置的直接性能更流程了。