【docker】容器中启动syslog
公司代码用了syslog,但由于一般公版的docker基础镜像里并没有syslog服务器。因此需要做个单独安装。
启动镜像后执行如下命令,即可完成syslog服务的安装和启动。
apt update && apt install rsyslog -y
rsyslogd
通过一下命令测试一下
logger "test"
在/var/log/syslog中出现了刚才的日志就说明服务安装成功。
公司代码用了syslog,但由于一般公版的docker基础镜像里并没有syslog服务器。因此需要做个单独安装。
启动镜像后执行如下命令,即可完成syslog服务的安装和启动。
apt update && apt install rsyslog -y
rsyslogd
通过一下命令测试一下
logger "test"
在/var/log/syslog中出现了刚才的日志就说明服务安装成功。
在用户角度来看,linux有两种信号量,system v和posix两种。
之前由于需要快速开发出东西来,就随便选了一个信号量来使用,后来才发现是system v,在使用过程中也遇到了一些坑。
sem_key_ = ftok(“file_exist”, 'a');
int flag = 0666;
flag |= IPC_CREAT;
sem_id_ = semget(sem_key_, 1, flag);
if (-1 == sem_id_) {
std::cout << "semaphore create failed" << std::endl;
return;
}
union semun sem_union;
sem_union.val = 1;
if (semctl(sem_id_, 0, SETVAL, sem_union) == -1) {
std::cout << "semaphore semctl failed" << std::endl;
return;
}
这里需要注意的是,ftok的第一个传入函数必须要某个存在的文件,因为需要通过具体的文件,去访问对应的nodeid,并做hash值。如果文件不存在,那么返回值将会是-1。
公司大佬用cudnn写了一个推理库,用于做背景分割。新到一台用于做测试的服务器,但sre和it都不管我,而我又是集成这个cudnn的人。所以只能自己亲自上,淡然还有大佬的帮助下成功安装了系统和驱动。
准备工作,一个新安装的ubuntu server 18。
下载好驱动、cuda、cudnn、tensorrt:
NVIDIA-Linux-x86_64-418.165.02.run
cuda-repo-ubuntu1804-10-1-local-10.1.243-418.87.00_1.0-1_amd64.deb
cuda-ubuntu1804.pin
libcudnn7_7.6.5.32-1+cuda10.1_amd64.deb
libcudnn7-dev_7.6.5.32-1+cuda10.1_amd64.deb
nv-tensorrt-repo-ubuntu1804-cuda10.1-trt6.0.1.5-ga-20190913_1-1_amd64.deb
其中需要注意的是,除了显卡驱动,其他部分都要下deb包,否则会出现打不上的情况。
然后按照教程的路线,执行dkpg -i和api install就好
因为不是做cuda相关开发,临时被拿来做调试一些相关代码。看到官方的一些介绍并不是很清晰,并没有完全说明cuda计算单元和nvenc/nvdec关系。仅仅提到nvenc和nvdec是两个编解码引擎。
并且还对特定显卡做了nvdec和nvenc的限制,对于一些老卡上,并没有nvdec和nvenc引擎。
官方给出的定义是nvdec、nvenc是独立于cuda核心,并不是很理解。或许nvdec和nvenc是相对于cuda核心的单纯的计算功能而划分出来给视频编解码使用的一个特定模块。
上网查了一下,以前的GPU加速编解码,实际上是利用cuda计算单元做一些数学计算,加快编解码速度。而nvenc和nvdec可以直接未编码数据或已编码数据进行处理。
那么这里就很好奇了,nvenc是一个单独的物理模块,还是一个逻辑模块。
通过对比实验发现还是稍有区别:
通过nvidia-smi dmon,可以发现除了流处理使用率有所增长,在程序初始化初期,从数据是上来看,可以推测nvenc和nvdec实际上还是利用到了部分流处理器,至于把这些流处理器拿来做什么就不得而知,也许只是作为解码初始化的一些树的加速计算,也许仅仅是被划分到nvenc、nvdec中参与编解码工作。
后续还需要一些相应深入和系统性的了解才好做判断。
用信号量来做共享内存的互斥操作,执行semop阻塞式调用。
结果发现执行p操作(加锁)会较低概率不定期的出现EINTR失败,查看linux手册,看到如下片段:
也就是当线程正在对信号量进行操作时,刚好出现该线程捕捉到了一个信号,这时候刚好接收到某个信号执行了相应信号的相应中断处理函数。
这主要是由于信号是以进程为单位,而具体某个信号会被进程内部的哪一个线程执行,这是极有可能不可预知的(主要有操作系统而定)。因此在这种情况下时,如果semop执行出现了一个EINTR错误,那么只需要再次重启调用semop就好。
解决这个问题的办法有两个:
1,通过屏蔽掉大部分该线程不关心的信号来解决,但是这样有可能会出现误屏蔽的操作情况。
2,单独开启一个线程来执行sigwait,作为信号处理线程。
最近在查coredump的时候,一直发现堆栈不完整。于是很好奇abort的信号默认情况下会如何处理。
网上查了一下,发现信号分为进程间信号和多线程间信号。
进程间信号,即进程之间可以互发信号,也可以进程内部某个线程来产生信号。由系统库提供支持。
多线程间信号,即线程之间互发信号,且指定具体线程来接收并处理。由pthread库提供支持。
由于coredump的抓取过程,应该没有做过特殊处理,因此使用的就是进程间信号。那么进程内,当某个线程执行某个代码时,产生了abort信号,信号会由谁来负责处理?实际测试的结果是由具体产生abort信号的线程来处理执行。
查了一下网上的解释,信号的处理,是由内核态准备切换回用户态时来处理,由于在态切换时,主动地插入了一个函数跳转指令,进而转为执行信号处理函数。因此由产生abort信号的线程来处理实现即简单,也符合逻辑。
由于是中断处理,这一点上可以看做和windows类似。
在写代码的时候,有一些技巧和方法已经快成为成为了众矢之的,主要还在于代码的可阅读性,以及易错性上。
被列为经典的几种方法或技巧中有一些还是能用尽量少用:goto、递归、状态机。
写过汇编的人都知道,汇编改变指令执行地址的方法里,除了call/ret,还有大量的jmp/sjmp来构成一个程序,如果仅仅使用call/ret来写,有时候代码会变得非常臃肿,而且让本来就难以理解的汇编变成更难阅读的代码,所以就会用jmp/sjmp来改变指令执行的地址。当然这只是抛砖引玉,在汇编里改变指令执行地址可不仅仅这两对指令,还有很多其他指令和方法。
而goto是我在学c语言的时候接触到的,c++也依然部分支持(具体看编译器和相应语言标准)。goto更像是汇编中变成思维的一种移植,类*inx系统的内核代码里也拥有大量的goto使用。
在面向过程变成里,使用goto似乎并没有太大不适,而且也能在一定程度上减少代码规模。但goto若用的不好,带来的效果适得其反。而且容易使得代码逻辑变得极其复杂,非常的绕思维。
goto在短小精干的代码里,可以较少的带来阅读和易错现象,而且要把goto用的好,用的巧妙,还非常考验写代码的人如何编排代码流程和排版。
若没有过硬的逻辑思维能力和计算机式的思维能力,goto能避免最好避免,尤其是在写一些对代码体积和性能要求不是太高的情况下。
代码的性能和体积其实可以通过其它方式优化,未必非要这样。
在数据结构和一些基本算法的教学里,递归是用的最频繁的。因为一些解题思路用递归来执行比较接近人类的思维方式,更容易理解。
栈帧的维护和执行,也是通过递归的方式进行的;可见递归的重要性。但是递归还存在容易让栈空间溢出,以及无限递归的出现,同样也存在一些不便于理解代码的情况。因为每一次递归函数的重入,都会使用新的栈帧对象,导致局部变量不是同一个的现象,这恰恰很有可能会让人在无意间错会递归的过程。
若不是解决问题的模型比较接近递归或代码短小精干的情况下,能用别的方式化解递归,最好通过其它方式。
状态机是一个基本的原型机或记录器,要从时间的角度出发讨论,状态机应该最先出现在高频模拟电路里,一些信号同步机制与触发应该是最接近状态机思维。
只不过后面称做状态机的都是从数字电路开始,状态机在设计门电路时,是最好用的一种分析工具或辅助工具。但在协议栈、驱动、直接和硬件交互的代码里,往往有着很多的状态机。
状态机由于仅仅是表征一种状态跃迁并联系成一个系统的工具,并未对状态跃迁的规则做约束,因此状态机很有可能会被设计的非常复杂,详情可以参考协议栈代码。若是过于强调状态机的特性,在写一些复杂度较高的策略模型时,往往是容易简单问题复杂化,甚至力不从心。
建议将状态机解耦,改为状态化就好。接触每种一状态之间的耦合度,会让代码较为简单些,如非常强调性能,可以通过其它方式解决。
最近在ios上出现将多个sdk放到一个app时,有各种开源静态库冲突的问题;于是考虑将自己用到的库进行打包成动态库版本,以此解决冲突问题。
在进行打包成动态库时,发现x264问题最大。打包出来的库在链接期出现text relocations错误,网上找了以后发现基本都是进行忽略这个错误,事实上这个错误忽略了没用,app启动时还是会出现相应的crash。
换了几个版本的xcode进行测试,发现x264编译会出现不同情况的告警和错误,根据底部罗列的参考文章,估计xcode的编译器可能也有一些bug。
后来模仿android上的编译方式,在x264里加入了–enable-pic和–disable-asm顺利编译通过,但由于osx和xcode版本的因素,模拟器上的并没有编译出来,仅仅编译了armv7和arm64。
参考文章:
MacOSX下编译linphone(text-relocation错误说明)
libxxx.so- text relocations问题的终极解决方案(android)
最近被安排来搞定android、ios、mac、windows下的webrtc、ffmpeg和x264的编译问题。
除了由于webrtc配置工程的问题在windows下我自己的搭建环境无法使用,最终求助于之前使用的虚拟机环境以外,android下的webrtc都比较顺利,同样也是编译anroid环境的和windows环境的ffmpeg,相对来说也是比较顺畅(虽然还是出现了一些坎坷)。
但在Mac环境下编译webrtc、ffmpeg和x264就没有那么幸运了。简直就是人间地狱,首先说明一下,这个Mac机原先是有其他开发者在上面编译成功过这三个工程的,到我之后就开始出现了一大堆问题(当然也有可能我用的是用户新帐号的缘故)。
最后去查config.log,发现一堆错误,其中ffmpeg的错误还有一个叫做gas-preprocessor.pl的执行错误,由于是通过git直接从网上拿下来的脚本,在没有任何修改的情况下,通过sftp发到mac里面,给了执行权限之后通过命令行直接执行一点问题都没有,但通过configure执行时就一直报没有权限的错,怎么也想不明白;后来试着用curl拿文件,居然通了。当时我就估计如果不是字符集的问题,就是权限标记位的问题。
接着再继续修改关于依赖的问题,仅仅一个交叉编译工具clang,居然在不同的工程里面对同一个路径参数能够出现多种不同的行为,后来还特意看了一下clang是不是GNU开源社区的代码,通过–version看到的内容如下:
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin16.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
可见这个坑是苹果自己的。可能是由于命令行的长度的不同,导致解析命令行的bug?或者其他什么坑爹问题?反正我是不知道了,近几年开始苹果的产品也不见得有多少优势了,正在被一点点拉小差距。如果不是为了混口饭吃,苹果的任何产品我真的不想去碰!
首先,我是一个完全的linux开发初学者,我仅仅在windows做开发,由于兴趣与工作的缘故碰到了通过已有的socket模型搭建好的网络库。下面就说说在windows下,我了解到socket模型(准确是标准socket模型,对于微软封装过的一些模型我不是很清楚)
1,普通阻塞是socket:
普通的socket模型,就是msdn中对socket api族介绍中最简单的那个例子。这种最简单,在执行效率上相对较低,在处理send/recv(sendto/recvfrom)时,函数是处于阻塞的。在简单环境,或者写一些简单的测试工具时,这是一种比较理想的用法。
2,同步 select模型
同步select模型,其实可以是理解为普通阻塞式sokcet的一个扩展,就是利用select来对socket句柄进行监听,避免由于调用send/recv(sendto/recvfrom)时出现阻塞。
3,异步select模型
异步select模型,可以看成是同步select的一种变化。即send/recv(sendto/recvfrom)函数不会阻塞,调用立即返回,并需要同时配合select函数一同使用。
4,IOCP
异步IO模型,使用上可以和异步select模型类比;但这并非标准socket模型。
然后接下来再说一下几个模型的差别:
1,普通socket、select模型,在调用send/recv(sendto/recvfrom)函数时,均会出现一次多余的内存拷贝。即,用户态传如一个buffer时,在转为交给协议栈之前,必须通过内存拷贝的方式,将数据复制到内核态的内存中。
2,windows上select集合最大值大约是64/128(有系统版本决定);换句话说一个调用select函数的线程,最大可监听64/128个socket句柄
*3,据网上各种文档介绍到,select是基于内核态线程轮询完成,具体不详,有待考证!
4,IOCP 和其他几者最大区别在于内存拷贝上,由于IOCP是通过共享内存(即内存映射)。在windows中内存映射属于一个特殊的内存管理器的管辖范围,他即不属于内核态,也不属于用户态内存,当对于内核态或用户态线程来说,只要通过调用内存映射函数,就可以直接访问这块内存(但得到的逻辑地址或许是不同的)。
由于在WSARecv/WSASend之类函数中,提交的均为共享内存,因此无需做任何内存拷贝。所以在IOCP上,性能要更好的多。同时本人的了解范畴也仅限于这一块,对于IOCP的事件投递过程并不是很清楚,但根据《软件调试》一书中对“windows系统调试/windows软件调试”设计的讲述来看,IOCP这种的实现应该是在内核态也同样创建了和用户态以之对应的内核服务线程。
接着再说说linux,刚刚看了一下epoll的介绍。
发现epoll是基于事件回调+内存映射来实现IO上的高效;同时这篇文章也还介绍了几个常用的socket模型在linux中的大概实现。通过这篇文章至少能够看出,linux和windows在对socket的实现上存在很大的相似。
可见linux和windows存在很多相似的地方,如果linux和windows互相对应着学,理解起来可能会快很多。
在编译ffmpeg的时候,发现libx264的so无法加载;后来发现加载的so位置不对。
通过ldd可以查看可执行文件以来的so文件极其位置,执行后命令输出如下:
aaa@debian-dev:~/dev_mobile$ ldd 'ffmpeg' linux-gate.so.1 => (0xb77be000) libx264.so.142 => /lib/libx264.so.142 (0xb75d9000) libm.so.6 => /lib/i386-linux-gnu/i686/cmov/libm.so.6 (0xb75b3000) libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0xb7599000) librt.so.1 => /lib/i386-linux-gnu/i686/cmov/librt.so.1 (0xb7590000) libpthread.so.0 => /lib/i386-linux-gnu/i686/cmov/libpthread.so.0 (0xb7577000) libc.so.6 => /lib/i386-linux-gnu/i686/cmov/libc.so.6 (0xb7413000) libdl.so.2 => /lib/i386-linux-gnu/i686/cmov/libdl.so.2 (0xb740f000) /lib/ld-linux.so.2 (0xb77bf000)
以前做过一段时间的LLT,对于LLT的实现感觉很奇怪。
LLT主要是用于函数单元级测试,以及多函数之间的debug。
在测试某个函数时,其实关心的只是函数本身流程和值计算是否正确。对于被函数如何调用其他函数,或者调用是否正确都不关心。因此需要对被测函数内部的函数调用情况作修改。
在windows上面,就用用到了hook中的一种。插入api,即替换函数的第一条汇编指令。
今天去看了那些招聘会,回来的路上感觉到,还是有些地方需要重新鉴定一下。现在有很多的企业都在招C++程序员,只可惜大部分都是基于.net环境的。
之所以会招.net环境的人,那是因为和.net的发展有关联。其实,.net应该是来源于2种语言。一种是C另一种还是VB,提出.net的概念的时候,本来就只是打算升级ASP所存在的一些弊端。
听说了,C++,有好几个方言版本。但就是.net的开发速度最快,效率也未必最高。反而一些牛XX企业,也许正喜欢用别的方言版本。MS的东西,我真的不敢恭维。再进一步弱化用户的同时,有时候也在某种程度上在弱化程序员。
由于学校的学生科研项目。由于自己对自己想法的偏执。网友的推荐,我开始学习了unix环境编程.
这本书一开始也没有注意。后来看着看才发现这本书是10年前写的。书里面讲的内容很多,很详细(对于我这个非计算机专业的人来说)。不过一样还是需要具备一些基础知识。
首先,至少需要知道什么是*inx。我是在debian环境里面熟悉linux的。同时手头还有一本linux内核讲解的书籍。当然这本书也是一样的很难。由于专业问题,看着非常的吃力。有时候还有不想看,自己逃避过很长的一段时间。不过毕竟是我向往的工作。linux嵌入式系统。所以还是在某种动力下,看了linux和unix的这两本书。
看的时候的确很痛苦,不过当我坚持出来的时候。我发现很多事情变得容易得多了。目前还没看完。以后很多我觉得重点的东西我一样会放上来,就算作为备忘录也是很好的。