分类目录:摩登3平台开户

摩登三1960_为了追求更快,CPU、内存、I/O都做了哪些努力?

背景 曾经,我面试的时候有两个最怕的。一怕问算法,二怕问高并发。 算法这个,刷了不少LeetCode,发现还是有套路可循的,虽不敢说算法能力有多强,至少没有以前那么怕了(才怪)。 而第二个,高性能高并发技术,感觉有好多技术要学,东学一点,西学一点,不成体系。直到有一次面试,遇到了一个大牛,问到了这方面,结果被虐的体无完肤。幸运的是,这位大牛不但技术一流,还认真跟我交流了学习心得,怎么样去有体系的系统去梳理这方面的技术知识,而不是瞎学。 CPU 不管什么样的编程语言,什么样的代码框架,最终都是由CPU去执行完成的(当然这么说不太准确,也有GPU、TPU、协处理器等其他情况,当然这不是本文探讨的重点)。 所以要想提高性能,提高并发量,首要问题就是如何让CPU跑的更快? 这个问题,也是一直以来CPU厂商一直在努力追求的方向。 如何让CPU更快?CPU厂商做了两个方面的努力: 加快指令执行的速度 加快CPU读取数据的速度 对于第一个方向,CPU执行指令的快慢,是跟CPU的主频紧密相关的,如何更快的取指令、指令译码、执行,缩短CPU的指令周期,提升主频在相当长一段时间里都是非常有效的办法。 从几百MHz,到如今到几GHz,CPU主频有了长足的进步,相同时间里能够执行的指令数变的更多了。 对于第二个方向,如何提升CPU读取数据的速度,答案就是加缓存,利用局部性原理将内存中经常会访问的数据搬运到CPU中,这样大大提升了存取速度。 从一级缓存,到二级缓存,乃至三级缓存,CPU缓存的层级和容量也在不断提升,读写数据的时间省了不少。 但随着时间到推移,尤其进入21世纪之后,处理器厂商发现,进一步提升主频变得越来越困难了,CPU的缓存也很难进一步扩容。 怎么办呢?既然一个人干活的速度已经很难再提升,那何不多找几个人一起干?于是,多核技术来了,一个CPU里面有多个核心,众人划桨开大船,CPU的速度再一次腾飞~ 甚至,让一个核在“闲暇时间”,利用“闲置资源”去执行另外的线程,诞生了让一个核“同时”执行两个线程的超线程技术。 上面简单交代了为了提升性能,CPU所做的努力。但是光是CPU快是没用的,还需要我们更好的去利用开发,否则就是对CPU算力的浪费。 上面提到了线程,是的,如何提高性能,提高并发量?使用多线程技术当然是一个非常好的思路。 但多线程的引入,就不得不提到两个跟线程有关的话题: 线程同步 线程阻塞 多个线程协同工作,必然会引入同步的问题,常规解决方案是加锁,加锁的线程一般会进入阻塞。 线程遇到阻塞了,就需要切换,而切换是有一定的成本开销的,不仅是系统调度的时间开销,还可能有CPU缓存失效的损失。 如果线程频频加锁,频频阻塞,那这个损失就相当可观了。为了提升性能,无锁编程技术就出现了,利用CPU提供的机制,提供更轻量的加锁方案。 同时,为了让切换后的线程仍然能够在之前的CPU核心上运行,降低缓存损失,线程的CPU亲和性绑定技术也出现了。 现代操作系统都是以时间片的形式来调度分配给多个线程使用。如果时间片还没用完就因为这样或那样的原因将执行机会拱手相让,那线程也太亏了。 于是,有人提出要充分利用CPU,别让线程阻塞,交出执行权,自己在应用层实现多个执行流的调度,这里阻塞了,就去执行那里,总之要把时间片充分用完,这就诞生了协程技术,阻塞了不要紧,我还能干别的,不要轻易发生线程切换。 内存 与CPU工作相关的第一亲密伙伴就是内存了,二者协作才能唱好一出戏。 提升内存访问的速度,同样是高性能开发话题重要组成部分! 那如何提升呢?硬件层面程序员是很难改变的,咱们只好从软件层面下功夫。 内存的管理经历了从实地址模式到分页式内存管理,如今的计算机中,CPU拿的的地址都是虚拟地址,这中间就会涉及到地址的转换,在这里就有文章可做,有两个方向可以努力: 减少缺页异常 使用大页技术 现代操作系统,基本上都会使用一个叫换页/交换文件的技术:内存空间有限,但进程越来越多,对内存空间的需求越来越大,用完了怎么办?于是在硬盘上划分一块区域出来,把内存中很久不用的数据转移到这块区域上来,等程序用到的时候,触发访问异常,再在异常处理函数中将其从硬盘读取进来。 可以想象,如果程序访问的内存老是不在内存中,而是被交换到了硬盘上,就会频繁触发缺页异常,那程序的性能肯定大打折扣,所以减少缺页异常也是提升性能的好办法。 从虚拟地址寻址真实的物理内存,这个过程是CPU完成的,具体来说,就是通过查表,从页表->一级页目录->二级页目录->物理内存。 页目录和页表是存在内存中的,毫无疑问,内存寻址是一个非常非常高频的事情,时时刻刻都在发生,而多次查表势必是很慢的,有鉴于此,CPU引入了一个叫TLB(Translation Look- aside buffer)的东西,使用缓存页表项的方式来减少内存查表的操作,加快寻址速度。 默认情况下,操作系统是以4KB为单位管理内存页的,对于一些需要大量内存的服务器程序(Redis、JVM、ElascticSearch等等),动辄就是几十个G,按照4KB的单位划分,那得产生多少的页表项啊! 而CPU中的TLB的大小是有限的,内存越多,页表项也就越多,TLB缓存失效的概率也就越大。所以,大页内存技术就出现了,4KB太小,就弄大点。大页内存技术的出现,减少了缺页异常的出现次数,也提高了TLB命中的概率,对于提升性能有很大的帮助。 在一些高配置的服务器上,内存数量庞大,而CPU多个核都要通过内存总线访问内存,可想而知,CPU核数上去以后,内存总线的竞争势必也会加剧。于是NUMA架构出现了,把CPU核心划分不同的分组,各自使用自己的内存访问总线,提高内存的访问速度。 I/O CPU和内存都够快了,但这还是不够。我们的程序日常工作中,除了一些CPU密集型的程序(执行数学运算,加密解密,机器学习等等)以外,相当一部分时间都是在执行I/O,如读写硬盘文件、收发网络数据包等等。 所以,如何提升I/O的速度,是高性能开发技术领域一个重要的话题。 因为I/O会涉及到与外设(硬盘、网卡等)的交互,而这些外设又通常是非常慢(相对CPU执行速度)的,所以正常情况下,线程执行到I/O操作时难免会阻塞,这也是前面在CPU部分提到过的。 阻塞以后那就没办法干活了,为了能干活,那就开多个线程。但线程资源是很昂贵的,没办法大量使用,况且线程多了,多个线程切换调度同样是很花时间的。 那可不可以让线程执行I/O时不阻塞呢?于是,新的技术又出现了: 非阻塞I/O I/O多路复用 异步I/O 原来的阻塞I/O是一直等,等到I/O的完成,非阻塞I/O一般是轮询,可以去干别的事,过一会儿就来问一下:好了没有? 但每个线程都去轮询也不是个事儿啊,干脆交给一个线程去专门负责吧,这就是I/O多路复用,通过select/poll的方式只用一个线程就可以处理多个I/O目标。再然后,再改进一下,用epoll,连轮询也不用了,改用内核唤醒通知的机制,同时处理的I/O目标还更多了。 异步I/O就更爽了,设置一个回调函数,自己干别的事去了,回头操作系统叫你来收数据就好了。 再说回到I/O本身,会将数据在内存和外设之间传输,如果数据量很大,让CPU去搬运数据的话,既耗时又没有技术含量,这是对CPU算力的很大浪费。 所以,为了将CPU从中解放出来,又诞生了一门技术:直接内存访问DMA,把数据的传输工作外包出去,交由DMA控制器来完成,CPU只在背后发号施令即可。 有了DMA,再也不用麻烦CPU去执行数据的搬运工作。但对于应用程序而言,想要把文件通过网络发送出去,还是要把数据在内核态空间和用户态空间来回折腾两次,这两步还得CPU出马去复制拷贝,属于一种浪费,为了解决这个问题,提升性能,又进一步产生了零拷贝技术,彻底为CPU减负。 算法架构 CPU、内存、I/O都够快了,单台计算机的性能已经很难提升了。不过,现在的服务器很少是单打独斗了,接下来就要把目光转移到算法、架构上来了。 一台服务器搞不定,那就用硬件堆出性能来,分布式集群技术和负载均衡技术就派上用场了。 这年头,哪个后端服务没有数据库?如何让数据库更快?该轮到索引技术上了,通过给数据库建立索引,提升检索速度。 但数据库这家伙的数据毕竟是存在硬盘上的,读取的时候势必会慢,要是大量的数据请求都怼上来,这谁顶得住?于是基于内存的Redis、Memcached应运而生,毕竟,访问内存比从数据库查询快得多。 算法架构这一块的技术实在太多了,也是从一个普通码农通往架构师的必经之路,咱们下回再聊。 高性能、高并发是后端开发永恒追求的话题。 每一项技术都不是凭空出现的,一定是为了解决某个问题而提出。我们在学这些技术的时候,掌握它出现的原因,和其他技术之间的关联,在自己的大脑中建立一座技术知识层级图,一定能事半功倍。 长按订阅更多精彩▼ 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3测速代理_一个工程师的“噩梦”:刚分清CPU和GPU,却发现还有……

01 先了解什么是异构并行计算 同构计算是使用相同类型指令集和体系架构的计算单元组成系统的计算方式。 而异构计算主要是指使用不同类型指令集和体系架构的计算单元组成系统的计算方式,常见的计算单元类别包括CPU、GPU、DSP、ASIC、FPGA等。 异构计算用简单的公式可以表示为“CPU+XXX”。举例来说,AMD着力发展的APU就属于异构计算,用公式表示就是CPU+GPU。 由于术业有专攻,CPU、GPU、DSP、ASIC、FPGA各有所长,在一些场景下,引入特定计算单元,让计算系统变成混合结构,就能让CPU、GPU、DSP、FPGA执行自己最擅长的任务。 异构计算(Heterogeneous Computing)在80年代中期就已产生,其定义更加宽泛。异构计算主要是指使用不同类型指令集和体系架构的计算单元组成系统的计算方式。常见的计算单元类别包括CPU、GPU等协处理器、DSP、ASIC、FPGA等。一个异构计算平台往往包含使用不同指令集架构(ISA)的处理器。   从软件的角度来讲,异构并行计算框架是让软件开发者高效地开发异构并行的程序,充分使用计算平台资源。从硬件角度来讲,一方面,多种不同类型的计算单元通过更多时钟频率和内核数量提高计算能力;另一方面,各种计算单元通过技术优化(如GPU从底层架构支持通用计算,通过分支预测、原子运算、动态并行、统一寻址、NIC直接访问显存等能力)提高执行效率。  正是因为异构计算在理论上有着诸多的优势,一些媒体将“CPU+XXX”称为下一代处理器。 异构计算在理论上相对于同构计算拥有很多优势——HSA能够简化芯片结构设计、降低应用编程门槛、缩短项目研发周期、显著提升芯片性能、广泛共享软件生态。 有厂家甚至宣传异构计算可以实现任何程序都不必费心考虑不同处理器内核之间的存储差异。但在现阶段,异构计算除了在超算上取得了明显成绩,在其他领域优势并不大。 即便异构计算目前还存在这样或那样的一些问题,但却是非常具有发展潜力的技术。 随着技术的进步,电子消费品市场对于高性能并行计算的需求正在爆发性增长,特别是在机器视觉、人工智能、云计算、AR/VR、软件定义无线电以及其他新兴领域,都对异构计算系统有着非常大的需求。 而HSA在系统编程方式上的迈进使得一个复杂片上系统能够协调在并行计算上比CPU更高效、更低功耗的GPU、DSP以及硬件加速器等计算单元承担大部分繁重的计算工作任务,在上述新兴领域能发挥较理想的作用。 也正是因此,Parmance公司计划与华夏芯在ML-HSA项目上进行合作——该项目面向机器学习和深层神经网络,并针对华夏芯此前发起的开源gccbrig项目进行优化,gccbrig项目为任何支持GCC的平台提供编译(终结转换)功能。 国外巨头也一直着力发展异构计算系统——Intel在去年以167亿美元收购阿尔特拉,发展CPU+FPGA,AMD着力发展的APU也属于异构计算,像Imagination、MTK等一些厂商也在异构计算领域积极布局。可以说,异构计算的市场前景还是值得期待。 02 再看看CPU与GPU的区别 随着GPU的可编程性不断增强,GPU的应用能力已经远远超出了图形渲染任务,利用GPU完成通用计算的研究逐渐活跃起来,将GPU用于图形渲染以外领域的计算成为GPGPU(General Purpose computing on graphics processing units,基于GPU的通用计算)。与此同时,CPU则遇到了一些障碍,CPU为了追求通用性,将其中大部分晶体管主要用于构建控制电路(比如分支预测等)和Cache,只有少部分的晶体管来完成实际的运算工作。 CPU + GPU 是一个强大的组合,因为 CPU 包含几个专为串行处理而优化的核心,而 GPU 则由数以千计更小、更节能的核心组成,这些核心专为提供强劲的并行性能而设计。程序的串行部分在 CPU 上运行,而并行部分则在 GPU上运行。GPU 已经发展到成熟阶段,可轻松执行现实生活中的各种应用程序,而且程序运行速度已远远超过使用多核系统时的情形。未来计算架构将是并行核心 GPU 与多核 CPU 共同运行的混合型系统。 1、CPU即中央处理器 CPU( Central Processing Unit, 中央处理器)就是机器的“大脑”,也是布局谋略、发号施令、控制行动的“总司令官”。 CPU的结构主要包括运算器(ALU, Arithmetic and Logic Unit)、控制单元(CU, Control Unit)、寄存器(Register)、高速缓存器(Cache)和它们之间通讯的数据、控制及状态的总线。 简单来说就是:计算单元、控制单元和存储单元,架构如下图所示: 图:CPU微架构示意图 从字面上我们也很好理解,计算单元主要执行算术运算、移位等操作以及地址运算和转换;存储单元主要用于保存运算中产生的数据以及指令等;控制单元则对指令译码,并且发出为完成每条指令所要执行的各个操作的控制信号。 所以一条指令在CPU中执行的过程是这样的:读取到指令后,通过指令总线送到控制器(黄色区域)中进行译码,并发出相应的操作控制信号;然后运算器(绿色区域)按照操作指令对数据进行计算,并通过数据总线将得到的数据存入数据缓存器(大块橙色区域)。 过程如下图所示: 图:CPU执行指令图 CPU遵循的是冯诺依曼架构,其核心就是:存储程序,顺序执行。 在这个结构图中,负责计算的绿色区域占的面积似乎太小了,而橙色区域的缓存Cache和黄色区域的控制单元占据了大量空间。 因为CPU的架构中需要大量的空间去放置存储单元(橙色部分)和控制单元(黄色部分),相比之下计算单元(绿色部分)只占据了很小的一部分,所以它在大规模并行计算能力上极受限制,而更擅长于逻辑控制。 另外,因为遵循冯诺依曼架构(存储程序,顺序执行),CPU就像是个一板一眼的管家,人们吩咐的事情它总是一步一步来做。但是随着人们对更大规模与更快处理速度的需求的增加,这位管家渐渐变得有些力不从心。 于是,能不能把多个处理器放在同一块芯片上,让它们一起来做事,这样效率不就提高了吗?GPU便由此诞生了。 2、GPU即图形处理器。 GPU全称为Graphics Processing Unit,中文为图形处理器,就如它的名字一样,GPU最初是用在个人电脑、工作站、游戏机和一些移动设备(如平板电脑、智能手机等)上运行绘图运算工作的微处理器。 为什么GPU特别擅长处理图像数据呢?这是因为图像上的每一个像素点都有被处理的需要,而且每个像素点处理的过程和方式都十分相似,也就成了GPU的天然温床。 GPU简单架构如下图所示: 图:GPU微架构示意图 从架构图我们就能很明显的看出,GPU的构成相对简单,有数量众多的计算单元和超长的流水线,特别适合处理大量的类型统一的数据。 但GPU无法单独工作,必须由CPU进行控制调用才能工作。CPU可单独作用,处理复杂的逻辑运算和不同的数据类型,但当需要大量的处理类型统一的数据时,则可调用GPU进行并行计算。 注:GPU中有很多的运算器ALU和很少的缓存cache,缓存的目的不是保存后面需要访问的数据的,这点和CPU不同,而是为线程thread提高服务的。如果有很多线程需要访问同一个相同的数据,缓存会合并这些访问,然后再去访问dram。 再把CPU和GPU两者放在一张图上看下对比,就非常一目了然了: GPU的工作大部分都计算量大,但没什么技术含量,而且要重复很多很多次。 借用知乎上某大神的说法,就像你有个工作需要计算几亿次一百以内加减乘除一样,最好的办法就是雇上几十个小学生一起算,一人算一部分,反正这些计算也没什么技术含量,纯粹体力活而已;而CPU就像老教授,积分微分都会算,就是工资高,一个老教授顶二十个小学生,你要是富士康你雇哪个? GPU就是用很多简单的计算单元去完成大量的计算任务,纯粹的人海战术。这种策略基于一个前提,就是小学生A和小学生B的工作没有什么依赖性,是互相独立的。 有一点需要强调,虽然GPU是为了图像处理而生的,但是我们通过前面的介绍可以发现,它在结构上并没有专门为图像服务的部件,只是对CPU的结构进行了优化与调整,所以现在GPU不仅可以在图像处理领域大显身手,它还被用来科学计算、密码破解、数值分析,海量数据处理(排序,Map-Reduce等),金融分析等需要大规模并行计算的领域。 所以,GPU也可以认为是一种较通用的芯片。 从根本上说CPU和GPU它们的目的不同,且有不同侧重点,也有着不同的性能特性,在某些工作中CPU执行得更快,另一工作中或许GPU能更好。当你需要对大量数据做同样的事情时,GPU更合适,当你需要对同一数据做很多事情时,CPU正好。 然而在实际应用中,后一种情形更多,也就是CPU更为灵活能胜任更多的任务。GPU能做什么?关于图形方面的以及大型矩阵运算,如机器学习算法、挖矿、暴力破解密码等,GPU会大幅提高计算效率。 Cache, local memory:CPU > GPU Threads(线程数): GPU > CPU Registers: GPU > CPU 多寄存器可以支持非常多的Thread,thread需要用到register,thread数目大,register也必须得跟着很大才行。 SIMD Unit(单指令多数据流,以同步方式,在同一时间内执行同一条指令): GPU > CPU。 简单地说,CPU擅长分支预测等复杂操作,GPU擅长对大量数据进行简单操作。一个是复杂的劳动,一个是大量并行的工作。 其实GPU可以看作是一种专用的CPU,专为单指令在大块数据上工作而设计,这些数据都是进行相同的操作,要知道处理一大块数据比处理一个一个数据更有效,执行指令开销也会大大降低,因为要处理大块数据,意味着需要更多的晶体管来并行工作,现在旗舰级显卡都是百亿以上的晶体管。 CPU呢,它的目的是尽可能快地在单个数据上执行单个指令。由于它只需要使用单个数据单条指令,因此所需的晶体管数量要少得多,目前主流桌面CPU晶体管都是十亿以下,和顶级GPU相差十倍以上,但它需要更大的指令集,更复杂的ALU(算术逻辑单元),更好的分支预测,更好的虚拟化架构、更低的延迟等等。 另外,像我们的操作系统Windows,它是为x86处理器编写的,它需要做的任务执行的进程,在CPU上肯定更为高效,你想每个线程的任务并不相同,基本上难以并行化,完全发挥不了GPU的长处。 总而言之,CPU和GPU因为最初用来处理的任务就不同,所以设计上有不小的区别。CPU的运算速度取决于请了多么厉害的教授。教授处理复杂任务的能力是碾压小学生的,但是对于没那么复杂的任务,还是顶不住人多。当然现在的GPU也能做一些稍微复杂的工作了,相当于升级成初中生高中生的水平。但还需要CPU来把数据喂到嘴边才能开始干活,最终还是靠CPU来管的。 03 CPU+GPU并行计算的好处 一 、CPU多核转到GPU并行化(适合算术密集型) 虽然GPU并不适用于所有问题的求解,但是我们发现那些对运算力量耗费巨大的科学命题都具备天然的特色。这类程序在运行时拥有极高的运算密度、并发线程数量和频繁地存储器访问,无论是在音频处理、视觉仿真还是到分子动力学模拟和金融风险评估领域都有大量涉及。这种问题如果能够顺利迁移到GPU为主的运算环境中,将为我们带来更高效的解决方案。 传统意义上的GPU不善于运行分支代码,但是ATI和NVIDIA经过长期改进其内部架构已经使得GPU可以较为高效地运行分支、循环等复杂代码。同时因为GPU属于并行机范畴,相同的运算可以应用到每个数据元素的时候,它们可以达到最好的性能。在CPU编程环境中,写出每个输入数据元素有不同数量的输入的程序很容易,但在GPU这种并行机上还是有不少麻烦。 通用的数据结构正是GPU编程的最大困难之一。CPU程序员经常使用的数据结构如列表和树在GPU身上并不容易实现。GPU目前还不允许任意存储器访问,而且GPU运算单元的设计为主要操作是在表现位置和颜色的四维向量上。 不过这些并不能阻挡GPU编程的加速发展,因为GPU不是真的为通用计算而设计的,需要一些努力才能让GPU高速地服务通用计算程序。这些努力前些年是程序员而单独实现的,而随着ATI和NVIDIA开始看到高性能计算市场的硬件需求,我们看到无论是Fermi架构添加全能二级缓存和统一定址还是RV870架构不断优化LDS并放大并发线程数,这些都是GPU自身硬件体系为了适应未来的运算环境而做出的变革。 二、并行化编程优点 在GPU并行编程过程中,OpenCL是一个不错的选择。OpenCL是Open Computing…

摩登3注册平台官网_嵌入式裸机编程中使用malloc、free会怎样?

在嵌入式裸机编程中,作为一名初级的CODER。经常要与CPU、内存等打交道。CPU作为系统的动力源,其重要程度不言而喻。 但是,在裸机编程中,对内存的管理也不容忽视。如果稍微不注意,轻则,可能造成内存泄漏,重则造成内存访问异常。导致系统死机。 嵌入式产品,对稳定性要求及其严格。动不动就死机,那可就麻烦大了。以下,是我本人对嵌入式系统裸机编程的内存管理的一些简介。 1、尽量不使用库自带的malloc和free。 malloc和free在PC编程中是很好用的一种内存分配手段。但是,其在嵌入式中,就未必好用了。由于嵌入式裸机编程中,无MMU,即内存管理单元。无法实现对内存进行动态映射(不明白什么叫动态映射的同学,可以参考网上的资料)。 也就是说,实际上,malloc和free并不能实现动态的内存的管理。这需要在启动阶段专门给其分配一段空闲的内存区域作为malloc的内存区。如STM32中的启动文件startup_stm32f10x_md.s中可见以下信息: Heap_Size EQU 0x00000800 AREA HEAP, NOINIT, READWRITE, ALIGN=3__heap_baseHeap_Mem SPACE Heap_Size__heap_limit 其中,Heap_Size即定义一个宏定义。数值为 0x00000800。Heap_Mem则为申请一块连续的内存,大小为 Heap_Size。简化为C语言版本如下: #define Heap_Size 0x00000800unsigned char Heap_Mem[Heap_Size] = {0}; 在这里申请的这块内存,在接下来的代码中,被注册进系统中给malloc和free函数所使用: __user_initial_stackheapLDR R0, = Heap_Mem ; 返回系统中堆内存起始地址LDR R1, =(Stack_Mem + Stack_Size)LDR R2, = (Heap_Mem + Heap_Size); 返回系统中堆内存的结束地址LDR R3, = Stack_MemBX LR 就如上面分析的那样,其实,在裸机编程的时候,对堆内存的管理。并非是智能化的,并非你想申请多少就多少。而是使用一块固定的内存用作堆内存的分配。这在设计的时候,往往不是最佳的方案。这块内存,如果被多次按照不同的大小进行申请,就会造成内存碎片。最终导致无法申请到足够的内存。导致系统运行出错。这在原本内存就已经很少的嵌入式系统中,更是不能接受的。所以,建议是把那个Heap_Size设置成 0 吧。放弃其使用吧。 而更为致命的是,有些malloc,free函数,由于工程人员的偷懒。实现甚至可能如下: unsigned char mem_buffer[512];unsigned char *mem_offset = & mem_buffer;void *malloc(int size){    unsigned char *tmp = mem_offset;    mem_offset += size;    return (void *)tmp;}void free(void *mem){ mem_offset = mem;} 2、不用malloc、free的原因 一般单片机的内存都比较小,而且没有MMU,malloc 与free的使用容易造成内存碎片。而且可能因为空间不足而分配失败,从而导致系统崩溃,因此应该慎用,或者自己实现内存管理。如:《一个简单而强大的单片机内存管理器》 在函数中使用malloc,如果是大的内存分配,而且malloc与free的次数也不是特别频繁,使用malloc与free是比较合适的,但是如果内存分配比较小,而且次数特别频繁,那么使用malloc与free就有些不太合适了。 因为过多的malloc与free容易造成内存碎片,致使可使用的堆内存变小。尤其是在对单片机等没有MMU的芯片编程时,慎用malloc与free。如果需要对内存的频繁操作,可以自己实现一个内存管理。 使用动态内存分配,应分不同的应用场合。 对于在操作系统上运行的程序,实际的物理内存分配与释放使用操作系统来实现的,即使程序调用了 malloc和free物理内存并不会马上变化。物理内存的变化,直到系统的内存管理操作时才发生。 对于裸机跑在MCU上的程序,分配与释放内存都会造成实际物理内存的变化。因为此时物理内存的分配是由自己实现的,而内存管理我们自己并没有去做。这样,盲目的使用malloc与free恰恰并不好,反而会造成内存的不恰当使用。甚至于内存溢出。 所以,动态内存的使用前提是有一套好的内存管理方法,这样动态内存的使用才会合理使用内存。如果没有合适的内存管理代码,还是用静态内存好一些。 3、 更好的替代方案:内存池。 可能有些同学,觉得:内存池,这是什么东西? 内存池,简洁地来说,就是预先分配一块固定大小的内存。以后,要申请固定大小的内存的时候,即可从该内存池中申请。用完了,自然要放回去。注意,内存池,每次申请都只能申请固定大小的内存。这样子做,有很多好处: (1)每次动态内存申请的大小都是固定的,可以有效防止内存碎片化。(至于为什么,可以想想,每次申请的都是固定的大小,回收也是固定的大小) (2)效率高,不需要复杂的内存分配算法来实现。申请,释放的时间复杂度,可以做到O(1)。 (3)实现简单,易用。 (4)内存的申请,释放都在可控的范围之内。不会出现以后运行着,运行着,就再也申请不到内存的情况。 内存池,并非什么很厉害的技术。实现起来,其实可以做到很简单。只需要一个链表即可。在初始化的时候,把全局变量申请来的内存,一个个放入该链表中。在申请的时候,只需要取出头部并返回即可。在释放的时候,只需要把该内存插入链表。以下是一种简单的例子(使用移植来的linux内核链表,对该链表的移植,以后有时间再去分析): #define MEM_BUFFER_LEN  5    //内存块的数量#define MEM_BUFFER_SIZE 256 //每块内存的大小//内存池的描述,使用联合体,体现穷人的智慧。就如,我一同学说的:一个字节,恨不得掰成8个字节来用。typedef union mem {struct list_head list;unsigned char buffer[MEM_BUFFER_SIZE];}mem_t;static union mem gmem[MEM_BUFFER_LEN];LIST_HEAD(mem_pool);//分配内存void *mem_pop(){    union mem *ret = NULL;    psr_t psr;    psr = ENTER_CRITICAL();    if(!list_empty(&mem_pool)) { //有可用的内存池         ret = list_first_entry(&mem_pool, union mem, list);        //printf("mem_pool = 0x%p  ret = 0x%p\n", &mem_pool, &ret->list);        list_del(&ret->list); } EXIT_CRITICAL(psr); return ret;//->buffer;}//回收内存void mem_push(void *mem){    union mem *tmp = NULL;     psr_t psr;    tmp = (void *)mem;//container_of(mem, struct mem, buffer);    psr = ENTER_CRITICAL();    list_add(&tmp->list, &mem_pool);    //printf("free = 0x%p\n", &tmp->list);    EXIT_CRITICAL(psr);}//初始化内存池void mem_pool_init(){    int i;    psr_t psr;    psr = ENTER_CRITICAL();    for(i=0; i         list_add(&(gmem[i]. list), &mem_pool);          //printf("add mem 0x%p\n", &(gmem[i].list));  }  EXIT_CRITICAL(psr); } 整理来自: 1、https://blog.csdn.net/chenyuwen789/category_5823163.html 2、https://blog.csdn.net/c12345423/article/details/53004465 免责声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。 最后 以上就是本次的分享,如果觉得文章不错,转发、在看,也是我们继续更新的动力。 猜你喜欢: 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3登录_Linux应用编程之动态库的制作与使用

关注、星标公众号,直达精彩内容 ID:嵌入式情报局 作者:情报小哥 1动态库制作和使用简介     在Linux中制作动态链接库只需要使用好GCC这两个编译选项即可搞定,下面小哥画了一张图简单的说明了下: 过程简要说明:     其实链接库的生成过程也可以先分别生成位置无关的目标文件.o文件,然后再创建生成最终的.so动态链接文件。不过gcc可以直接使用这两个编译选项一次性生成。 2动态链接库制作过程 01 准备源文件     这里小哥还是使用昨天的两个module作为例子来讲解动态链接过程,这里就不板书了,可以到上一节静态链接中查看源文件。 02 编译生成动态链接库     这里通过-fPIC和-shared两个选项即可把所有的.c文件生成libxxx.so文件。那下面看一下这两个选项是什么意思: > > > > -fPIC选项     PIC – Position Independent Code,意思是位置无关码,即加载器把其加载到内存任何位置,其代码均可以正常运行,所以代码中都是使用的是相对地址,这样的特点也就非常满足动态库加载位置变化的特性。     同时这样的特点也让动态库被多个应用程序连接的时候不需要copy形成多个副本,大大节省内存。 > > > > -shared选项    该选项主要是GCC把目标文件链接成为一个共享库。 03 使用库文件编译     这里使用共享库来生成可执行文件的用法和前面的静态链接库是类似的,-lxxx(其中的xxx即.so文件去掉lib和后缀的名称),-L.即表示在当前文件中链接共享库。 04 动态库的使用          如果直接运行可执行文件Test,系统会提示无法打开共享文件,那一般都是由于共享库没有在系统加载器所在指定的路径中。    一般加载器都会默认在”/lib”、”/usr/lib”后者LD_LIBRARY_PATH环境变量指定的路径中搜索动态库,所以如果把.so文件复制到前面两个目录便可执行,不过为了不破坏系统文件,一般都会使用环境变量定义路径。    上面小哥直接使用export设置了环境变量定义为了当前路径,通过”echo $xxx”便可以查看所设置的路径,当然你也可以使用unset来删除环境变量,然后再次运行程序即可获得跟上次静态链接库一样的结果了。     当然这里采用了最直接的环境变量设置方法,一般系统注销,该环境变量就会消失,后面小哥会再整理一下环境变量的设置包括如何长久保留环境变量等,比如在用户主目录下的.profile或.bashrc文件配置。 3小结     今天主要是跟大家介绍了动态链接库的制作和使用,下期精彩见。 最后以上就是本次的分享,如果觉得文章不错,转发、在看,也是我们继续更新的动力。猜你喜欢: 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3测速登录地址_干货!protobuf-c之嵌入式平台使用

什么是protobuf-c 之前的文章:《Protobuf:一种更小、更快、更高效的协议》详细介绍了protobuf及protobuf-c。这里再简单提一下: Protocol Buffers,是Google公司开发的一种数据格式,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。protobuf支持一些主流的语言,唯独没有支持C,所以诞生了第三方的protobuf-c。 之前文章介绍了protobuf、protobuf-c在PC平台上的安装及使用,本篇笔记我们来把它用在我们的嵌入式ARM平台。 交叉编译protobuf-c 之前的文章中我们已经把protobuf、protobuf-c安装在我们的PC环境中了: 我们简单回顾一下我们上一篇文章的大致内容: 从中我们知道,这里的protobuf的主要作用是生成了protoc工具,而protoc工具的作用是把.proto文件生成对应的C源、头文件,这个过程是与平台无关的,所以这里我们可以接着用。 而protobuf-c生成了编译需要用到的动态库,此处我们需要编译ARM架构的动态库。即我们本篇笔记需要做的事情是: (1)交叉编译protobuf-c 首先在protobuf-c目录下使用make clean命令清除我们之前编译得到的东西: 输入如下命令生成交叉编译的Makefile文件: 左右滑动查看全部代码>>> ./configure --host=arm-linux-gnueabihf CC=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-gcc CXX=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-g++ --disable-protoc --prefix=$PWD/tmp 这个命令似乎很长,但并不难,只是加了几个配置参数。这些配置参数怎么看?我们可以输入./configure --help命令来查看支持的配置: 下面我们依次来分析上面那个很长的命令: –host=arm-linux-gnueabihf:表明了我们最终可执行文件运行的环境。 CC=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-gcc:这是指定我们的交叉编译工具arm-linux-gnueabihf-gcc,这里直接给出绝对路径。 CXX=/home/book/ToolChain/gcc-arm-linux-gnueabihf-6.2.1/bin/arm-linux-gnueabihf-g++:这是指定我们的交叉编译工具arm-linux-gnueabihf-g++,这里直接给出绝对路径。 –disable-protoc:不使用protoc,前面我们也说了protoc工具把.proto文件生成对应的C源、头文件的过程是与平台无关的,所以这里不需要使用,除非我们想在我们的开发板上使用protoc,但这反而增加麻烦,不推荐直接在开发板上用。 –prefix=$PWD/tmp:指定安装的路径。表明安装路径在当前路径下的tmp文件夹中。 执行完这个命令之后就得到了交叉编译的Makefile文件,然后依次输入如下命令进行编译、安装: makemake install 此时就在当前目录的tmp文件夹下生成了arm版本的相关库文件: 其中我们比较重要的就是libprotobuf-c.so这个动态库了,我们可以使用file或者readelf工具查看其是不是arm格式的: 很显然,这就是我们ARM平台的动态库。关于readelf的使用相关文章:《简单认识认识ELF文件》 下面开始我们的demo演示: (2)protobuf-c实例演示 我们自定义一个.proto来创建我们的协议数据,然后使用protoc-c工具编译生成C代码,有两个文件:一个头文件、一个源文件。 例如我们创建一个student.proto文件: syntax = "proto2"; message Student{    required string name    = 1;    required uint32 num     = 2;    required uint32 c_score = 3;} 使用protoc-c工具工具编译student.proto文件: protoc --c_out=. student.proto 编写我们的student.c测试demo: 左右滑动查看全部代码>>> #include  #include  #include  #include "student.pb-c.h" int main(void){    Student pack_stu = {0};    uint8_t buffer[512] = {0};    Student *unpack_stu = NULL;    size_t len = 0;     student__init(&pack_stu);     /* 组包 */    pack_stu.name = "ZhengN";    pack_stu.num = 88;    pack_stu.c_score = 90;    len = student__pack(&pack_stu, buffer);    printf("len = %ld\n",len);     /* 解包 */    unpack_stu = student__unpack(NULL, len, buffer);    printf("unpack_stu.name = %s\n", unpack_stu->name);    printf("unpack_stu.num = %d\n", unpack_stu->num);    printf("unpack_stu.c_score = %d\n", unpack_stu->c_score);     student__free_unpacked(unpack_stu, NULL);    return 0;} demo很简单,组包就是构造一个协议数据结构体,调用pack组包接口往buffer中扔数据;解包正好是反过来,从buffer中拿数据放到结构体里。 此时我们工程的文件有: 交叉编译: 左右滑动查看全部代码>>> arm-linux-gnueabihf-gcc student.c student.pb-c.c -o student -I /home/book/git_clone/protobuf-c/tmp/include -L /home/book/git_clone/protobuf-c/tmp/lib -lprotobuf-c 这个命令似乎也很长,其实也很简单: arm-linux-gnueabihf-gcc:交叉编译器。 student.c student.pb-c.c:输入的源文件。 student:生成的可执行文件。 -I /home/book/git_clone/protobuf-c/tmp/include:指定头文件路径。 -L /home/book/git_clone/protobuf-c/tmp/lib:指定库路径。 -lprotobuf-c:链接动态库libprotobuf-c.so。 这里需要重点提的就是我们可以把我们上面编译得到的tmp/include里的文件复制到我们交叉编译器头文件搜索路径下、把tmp/lib里的文件复制到交叉编译器库文件搜索路径下,这样我们就不需要指定这么长的一串路径了。 但是这里我为了保持我的交叉编译器的一个原始性,我就不往里加东西了。关于这些链接、动态库更详细的内容可以阅读往期文章:《静态链接与动态链接补充(Linux)》、《什么是动态链接与静态链接?》 编译没问题的话就可以生成我们的可执行文件student: 同样的,我们可以看一下student可执行文件的运行环境: 可见,是可运行在我们的arm开发板的。 下面把student拷贝到我们的开发板上运行,我这里用的是韦东山老师的IMX6ULL开发板。 运行出现如下错误: 这是因为不能找到共享库文件libprotobuf-c.so1,加载失败,这个问题我们已经在《静态链接与动态链接补充(Linux)》一文中做了详细解释。 解决方法有两种:第一种就是把这个库文件拷贝至系统库默认搜索路径下;第一种就是把当前路径增加为动态库的搜索路径。 这里我们选择第二种方法:我们把libprotobuf-c.so、libprotobuf-c.so1也传到板子上,放在student同目录下。然后输入如下命令把当前路径增加为动态库的搜索路径: export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH 然后运行: 运行成功! 以上就是咱们介绍的protobuf-c在嵌入式Linux平台上的使用(如果是正在学单片机的朋友,也可以尝试着移植使用。),如有错误,欢迎指出,谢谢。 按照以上两篇文章的步骤,大概率是可以成功的,关键是有耐心。 心得分享:在Linux的学习中,很多时候会被开发环境阻碍我们。常常按照别人的方法、步骤来做,却做不出来,很容易心态崩,这都是很正常的。因为环境不同,有时候还需要各种依赖。但我们要有足够的耐心,见招拆招! 在此之前,我也遇到了很多问题,也搜索了很多博客文章,要么行不通,要么写得太乱。所以趁此学习、写一篇。 这一篇大概是全网第一篇关于protobuf-c在嵌入式Linux平台上的交叉编译、使用步骤最全、解释最多的文章了。如果文章对你有帮助,麻烦帮忙转发,谢谢大家。 最后 以上就是本次的分享,如果觉得文章不错,转发、在看,也是我们继续更新的动力。 猜你喜欢: Linux 的启动流程 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3注册登录网_干货分享!嵌入式裸机编程中使用malloc、free会怎样?

在嵌入式裸机编程中,作为一名初级的CODER。经常要与CPU、内存等打交道。CPU作为系统的动力源,其重要程度不言而喻。 但是,在裸机编程中,对内存的管理也不容忽视。如果稍微不注意,轻则,可能造成内存泄漏,重则造成内存访问异常。导致系统死机。 嵌入式产品,对稳定性要求及其严格。动不动就死机,那可就麻烦大了。以下,是我本人对嵌入式系统裸机编程的内存管理的一些简介。 1、尽量不使用库自带的malloc和free。 malloc和free在PC编程中是很好用的一种内存分配手段。但是,其在嵌入式中,就未必好用了。由于嵌入式裸机编程中,无MMU,即内存管理单元。无法实现对内存进行动态映射(不明白什么叫动态映射的同学,可以参考网上的资料)。 也就是说,实际上,malloc和free并不能实现动态的内存的管理。这需要在启动阶段专门给其分配一段空闲的内存区域作为malloc的内存区。如STM32中的启动文件startup_stm32f10x_md.s中可见以下信息: Heap_Size EQU 0x00000800AREA HEAP, NOINIT, READWRITE, ALIGN=3__heap_baseHeap_Mem SPACE Heap_Size__heap_limit 其中,Heap_Size即定义一个宏定义。数值为 0x00000800。Heap_Mem则为申请一块连续的内存,大小为 Heap_Size。简化为C语言版本如下: #define Heap_Size 0x00000800unsigned char Heap_Mem[Heap_Size] = {0}; 在这里申请的这块内存,在接下来的代码中,被注册进系统中给malloc和free函数所使用: __user_initial_stackheapLDR R0, = Heap_Mem ; 返回系统中堆内存起始地址LDR R1, =(Stack_Mem + Stack_Size)LDR R2, = (Heap_Mem + Heap_Size); 返回系统中堆内存的结束地址LDR R3, = Stack_MemBX LR 就如上面分析的那样,其实,在裸机编程的时候,对堆内存的管理。并非是智能化的,并非你想申请多少就多少。而是使用一块固定的内存用作堆内存的分配。这在设计的时候,往往不是最佳的方案。这块内存,如果被多次按照不同的大小进行申请,就会造成内存碎片。最终导致无法申请到足够的内存。导致系统运行出错。这在原本内存就已经很少的嵌入式系统中,更是不能接受的。所以,建议是把那个Heap_Size设置成 0 吧。放弃其使用吧。 而更为致命的是,有些malloc,free函数,由于工程人员的偷懒。实现甚至可能如下: unsigned char mem_buffer[512];unsigned char *mem_offset = & mem_buffer;void *malloc(int size){unsigned char *tmp = mem_offset; mem_offset += size;return (void *)tmp;}void free(void *mem){ mem_offset = mem;} 2、不用malloc、free的原因 一般单片机的内存都比较小,而且没有MMU,malloc 与free的使用容易造成内存碎片。而且可能因为空间不足而分配失败,从而导致系统崩溃,因此应该慎用,或者自己实现内存管理。如: 《一个简单而强大的单片机内存管理器》 在函数中使用malloc,如果是大的内存分配,而且malloc与free的次数也不是特别频繁,使用malloc与free是比较合适的,但是如果内存分配比较小,而且次数特别频繁,那么使用malloc与free就有些不太合适了。 因为过多的malloc与free容易造成内存碎片,致使可使用的堆内存变小。尤其是在对单片机等没有MMU的芯片编程时,慎用malloc与free。如果需要对内存的频繁操作,可以自己实现一个内存管理。 使用动态内存分配,应分不同的应用场合。 对于在操作系统上运行的程序,实际的物理内存分配与释放使用操作系统来实现的,即使程序调用了 malloc和free物理内存并不会马上变化。物理内存的变化,直到系统的内存管理操作时才发生。 对于裸机跑在MCU上的程序,分配与释放内存都会造成实际物理内存的变化。因为此时物理内存的分配是由自己实现的,而内存管理我们自己并没有去做。这样,盲目的使用malloc与free恰恰并不好,反而会造成内存的不恰当使用。甚至于内存溢出。 所以,动态内存的使用前提是有一套好的内存管理方法,这样动态内存的使用才会合理使用内存。如果没有合适的内存管理代码,还是用静态内存好一些。 可能有些同学,觉得:内存池,这是什么东西? 内存池,简洁地来说,就是预先分配一块固定大小的内存。以后,要申请固定大小的内存的时候,即可从该内存池中申请。用完了,自然要放回去。注意,内存池,每次申请都只能申请固定大小的内存。这样子做,有很多好处: (1)每次动态内存申请的大小都是固定的,可以有效防止内存碎片化。(至于为什么,可以想想,每次申请的都是固定的大小,回收也是固定的大小) (2)效率高,不需要复杂的内存分配算法来实现。申请,释放的时间复杂度,可以做到O(1)。 (3)实现简单,易用。 (4)内存的申请,释放都在可控的范围之内。不会出现以后运行着,运行着,就再也申请不到内存的情况。 内存池,并非什么很厉害的技术。实现起来,其实可以做到很简单。只需要一个链表即可。在初始化的时候,把全局变量申请来的内存,一个个放入该链表中。在申请的时候,只需要取出头部并返回即可。在释放的时候,只需要把该内存插入链表。以下是一种简单的例子(使用移植来的linux内核链表,对该链表的移植,以后有时间再去分析): #define MEM_BUFFER_LEN 5 //内存块的数量#define MEM_BUFFER_SIZE 256 //每块内存的大小//内存池的描述,使用联合体,体现穷人的智慧。就如,我一同学说的:一个字节,恨不得掰成8个字节来用。typedef union mem {struct list_head list;unsigned char buffer[MEM_BUFFER_SIZE];}mem_t;static union mem gmem[MEM_BUFFER_LEN];LIST_HEAD(mem_pool);//分配内存void *mem_pop(){ union mem *ret = NULL; psr_t psr; psr = ENTER_CRITICAL();…

摩登3新闻554258:_大厂也在用的6种数据脱敏方案,别做泄密内鬼

最近连着几天晚上在家总是接到一些奇奇怪怪的电话,“哥,你是 xxx 吧,我们这里是 xxx 高端男士私人会所…”,握草,我先是一愣,然后狠狠的骂了回去。一脸傲娇的转过头,面带微笑稍显谄媚:老婆你听我说,我真的啥也没干,你要相信我! 啪~ 搞事情啊 过后揉揉脸细想想,肯定是哪个不道德的网站,又把我的个人信息给卖了,现在的人上网都处于一个裸奔的状态,个人信息已不再属于个人,时下这种事好像也见怪不怪了,不过,出现这种事大多是有内鬼。 停止交易,有内鬼 而作为开发者的我们,能做的就是尽量避免经我们手的用户数据泄露,那今天就来讲讲互联网中内部防止隐私数据泄露的手段-数据脱敏。 什么是数据脱敏 先来看看什么是数据脱敏?数据脱敏也叫数据的去隐私化,在我们给定脱敏规则和策略的情况下,对敏感数据比如 手机号、银行卡号 等信息,进行转换或者修改的一种技术手段,防止敏感数据直接在不可靠的环境下使用。 像政府、医疗行业、金融机构、移动运营商是比较早开始应用数据脱敏的,因为他们所掌握的都是用户最核心的私密数据,如果泄露后果是不可估量的。 数据脱敏的应用在生活中是比较常见的,比如我们在淘宝买东西订单详情中,商家账户信息会被用 * 遮挡,保障了商户隐私不泄露,这就是一种数据脱敏方式。 淘宝详情 数据脱敏又分为静态数据脱敏(SDM)和 动态数据脱敏(DDM): 静态数据脱敏 静态数据脱敏(SDM):适用于将数据抽取出生产环境脱敏后分发至测试、开发、培训、数据分析等场景。 有时我们可能需要将生产环境的数据  copy 到测试、开发库中,以此来排查问题或进行数据分析,但出于安全考虑又不能将敏感数据存储于非生产环境,此时就要把敏感数据从生产环境脱敏完毕之后再在非生产环境使用。 这样脱敏后的数据与生产环境隔离,满足业务需要的同时又保障了生产数据的安全。 数据脱敏过程 如上图所示,将用户的真实 姓名、手机号、身份证、银行卡号 通过 替换、无效化、乱序、对称加密 等方案进行脱敏改造。 动态数据脱敏 动态数据脱敏(DDM):一般用在生产环境,访问敏感数据时实时进行脱敏,因为有时在不同情况下对于同一敏感数据的读取,需要做不同级别的脱敏处理,例如:不同角色、不同权限所执行的脱敏方案会不同。 注意:在抹去数据中的敏感内容同时,也需要保持原有的数据特征、业务规则和数据关联性,保证我们在开发、测试以及数据分析类业务不会受到脱敏的影响,使脱敏前后的数据一致性和有效性。。 数据脱敏方案 数据脱敏系统可以按照不同业务场景自行定义和编写脱敏规则,可以针对库表的某个敏感字段,进行数据的不落地脱敏。 脱敏系统 数据脱敏的方式有很多种,接下来以下图数据为准一个一个的演示每种方案。 原始数据 1、无效化 无效化方案在处理待脱敏的数据时,通过对字段数据值进行 截断、加密、隐藏 等方式让敏感数据脱敏,使其不再具有利用价值。一般采用特殊字符(*等)代替真值,这种隐藏敏感数据的方法简单,但缺点是用户无法得知原数据的格式,如果想要获取完整信息,要让用户授权查询。 截断方式 比如我们将身份证号用 * 替换真实数字就变成了 “220724 ****** 3523″,非常简单。 隐藏方式 2、随机值 随机值替换,字母变为随机字母,数字变为随机数字,文字随机替换文字的方式来改变敏感数据,这种方案的优点在于可以在一定程度上保留原有数据的格式,往往这种方法用户不易察觉的。 我们看到 name 和 idnumber 字段进行了随机化脱敏,而名字姓、氏随机化稍有特殊,需要有对应姓氏字典数据支持。 随机值 3、数据替换 数据替换与前边的无效化方式比较相似,不同的是这里不以特殊字符进行遮挡,而是用一个设定的虚拟值替换真值。比如说我们将手机号统一设置成 “13651300000”。 数据替换 4、对称加密 对称加密是一种特殊的可逆脱敏方法,通过加密密钥和算法对敏感数据进行加密,密文格式与原始数据在逻辑规则上一致,通过密钥解密可以恢复原始数据,要注意的就是密钥的安全性。 对称加密 5、平均值 平均值方案经常用在统计场景,针对数值型数据,我们先计算它们的均值,然后使脱敏后的值在均值附近随机分布,从而保持数据的总和不变。 原始数据 对价格字段 price 做平均值处理后,字段总金额不变,但脱敏后的字段值都在均值 60 附近。 平均值 6、偏移和取整 这种方式通过随机移位改变数字数据,偏移取整在保持了数据的安全性的同时保证了范围的大致真实性,比之前几种方案更接近真实数据,在大数据分析场景中意义比较大。 比如下边的日期字段create_time中 2020-12-08 15:12:25 变为 2018-01-02 15:00:00。 取整 数据脱敏规则在实际应用中往往都是多种方案配合使用,以此来达到更高的安全级别。 总结 无论是静态脱敏还是动态脱敏,其最终都是为了防止组织内部对隐私数据的滥用,防止隐私数据在未经脱敏的情况下从组织流出。所以作为一个程序员不泄露数据是最起码的操守。 长按订阅更多精彩▼ 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3平台首页_RSL10 Mesh平台荣获2020年度中国IoT创新奖之“IoT技术创新奖”

12月4日,由电子发烧友举办的第七届中国IoT大会于深圳举办。在当天晚上的中国IoT创新奖颁奖典礼上,安森美半导体的RSL10 Mesh 平台荣获“IoT技术创新奖”。 安森美半导体医疗分部亚洲区高级市场经理杨正龙(Henry Yang) RSL10 Mesh平台。这Strata赋能的方案提供智能感知和云联接,支持节点对节点通信。 使用RSL10 Mesh平台,工程师可轻松实现使用低功耗蓝牙技术的超低功耗的网状网络,并迅速走向全面部署。该多面方案优化用于智能家居、楼宇自动化、工业IoT、远程环境监控以及资产跟踪和监控应用,具有开发和部署网状网络所需的所有基本要素。 与传统的点对点 (P2P) 蓝牙联接不同,蓝牙低功耗网状网络实现了,比传统的P2P蓝牙通信覆盖更大的距离,因为节点可以将数据包中继到传输节点范围之外的目标节点以执行消息传递。 这使以前无法用蓝牙技术实现的各种IoT应用成为可能,包括联网照明和远程传感器监控。蓝牙低功耗网状网络的价值和消除范围限制,现已在工业、农业、企业和物流领域以及智慧城市的兴起等多个不同环境得以认可。 但是,运作限制和实施便利性仍是主要挑战。安森美半导体的RSL10 Mesh平台,以更快地部署节点,推进在范围、灵活性和功率预算的性能极限。 RSL10 Mesh平台基于超低功耗RSL10系统级封装(RSL10 SIP),含两个RSL10 Mesh节点和一个Strata网关,以联接到Strata Developer Studio™。 RSL10 SIP辅以一系列传感器和指示器,已集成到节点硬件中,包括环境光传感器(LV0104CS)、温度传感器(N34TS108)、磁性传感器、LED指示器和三路输出NCP5623B LED驱动器 (用于混色)。另外还内置一个电池充电器,适用于具有锂离子或锂聚合物化学性质的电池。 网格节点可以简单地配置成不同的角色并展示特定的功能面。与之配套的Strata 网关支持使用高度直观的Strata Developer Studio进行评估过程。这云联接的软件可实现更多网格的配置,并支持空中固件升级(FOTA)。 使用虚拟工作区用于包括智能办公室在内的常见网状网络示例,开发人员可以访问传感器数据和触发设置。该高能效RSL10无线电配以基于Eclipse的集成开发环境、用于预配、配置和控制低功耗蓝牙网状网络的移动应用程序,以及符合蓝牙特别兴趣小组(Bluetooth SIG)的网状网络软件包。 免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!

摩登3测速登陆_高通5G芯片骁龙888升级显著 GPU实现迄今为止最大提升

骁龙888全新的命名方式,也成为人们对这款高通5G芯片喜闻乐道的焦点。数字“8”在过去的十几年里一直代表着高通旗下最旗舰的产品层级。所以,这一次高通希望以一个“最能代表旗舰的命名”来赋予高通骁龙888这一款全新的5G芯片。 话不多说,让我们一起来领略高通这款迄今为止最强大5G芯片的秘密吧。 高通5G芯片骁龙888的Kryo 680 CPU采用了Arm今年5月刚刚发布的Cortex-A78、Cortex-X1内核,一个主频为2.84GHz的X1性能超大核+三个主频为2.4GHz的A78大核+四个主频1.8GHz的A55小核的三丛集设计,再加三星5nm制程加持,让高通5G芯片骁龙888具备极为出色的能效比。虽然高通5G芯片骁龙888在频率上保持和上代高通5G芯片骁龙865一致,但CPU综合性能还是提升了25%之多。高通一直注重CPU的持续性能,因为向其他友商一样单纯地追求“一两分钟”的高峰值性能,其实意义不大,只有持续稳定的性能才能给用户带来好的体验。 GPU方面,高通5G芯片骁龙888采用了Adreno 660 GPU,实现了迄今为止最大的性能提升,图形渲染速度的增幅高达35%之多。同样的,高通强调骁龙888 5G芯片的GPU也能够持续稳定输出高性能,这相比峰值性能更为重要。 再说说AI部分,高通5G芯片骁龙888采用了整体全新设计的第六代AI引擎,Hexagon 780处理器实现了Scalar、Tensor、Vector三个AI加速器之间的内存共享,拥有每秒26万亿次算力,性能增加了73%,每瓦特性能提升至前代的3倍。值得留意的是,第二代高通传感器中枢集成的专用低功耗AI处理器的运用,实现了低功耗(节能80%)与高效能的兼得。 拍照能力历来是高通骁龙芯片尤为重视的一个部分,高通5G芯片骁龙888首次采用了三ISP设计。现在智能手机普遍镜头数量都在三个以上,通过三ISP设计,高通5G芯片骁龙888可以让不同镜头调用不同的ISP,轻松实现10亿像素级的图像处理,每秒处理27亿像素,支持4K 120FPS不限时慢动作摄影。骁龙888的如此强大,以至于高通总裁安蒙就曾调侃道“高通是一家相机公司。” 当然,作为明年安卓旗舰智能手机的首选,高通5G芯片骁龙888更大的发力点还是在5G方面。高通5G芯片骁龙888完全集成了高通第三代5G调制解调器及射频系统——骁龙X60。骁龙X60是一个系统级的完整解决方案,包括基带、射频收发器、射频前端、毫米波天线模组,旨在为运营商提供极大的灵活性,最大化其可用的频谱资源。作为现阶段最全面的5G解决方案,高通骁龙X60 5G基带支持全球毫米波和Sub-6GHz全部主要频段,以及5G载波聚合、全球多SIM卡功能、独立(SA)和非独立(NSA)组网模式以及动态频谱共享(DSS),是真正面向全球的兼容性5G平台。在高通5G基带骁龙X60的加持下,高通5G芯片骁龙888能够支持5G在更多的国家得以部署,进一步提升终端整体性能和网络所提供的用户体验,以及解决随着时间而不断增加的频段组合的复杂性。 得益于高通5G基带骁龙X60在全球5G兼容性和对未来新技术的事先准备,高通5G芯片骁龙888既能保证消费者将来在全球各地的出差或旅游时,在不用换机的前提下,依然有高速5G网络可用,还会随着5G网络建设所采用的毫米波等技术,用户将获得更快的网速体验,不愧是现阶段最出色的5G基带。 目前,小米、vivo、realme、OnePlus、OPPO、黑鲨、联想、中兴等OEM产商都会推出搭载高通5G芯片骁龙888的手机产品,骁龙888的实际表现,很快就能在市场上见分晓。

摩登3登录网站_当收发器遇上外部本振,更强的射频性能get√

软件定义无线电是当今业界的主要话题之一。射频(RF)收发器在单芯片集成电路中(IC)中提供了完整的无线电解决方案,推动了软件定义无线电的领域的发展。ADI 收发器产品线推出了这类强大的芯片,正快速应用于许多通过软件控制的无线电设计中。但是如何获得较低的相位噪声仍是使用这些器件需要探索的领域之一。本文评估这些高度集成的射频集成电路(RFIC)的相位噪声性能,重点评估提供外部频率时的情况。 使用外部本振(LO)时对ADI公司 ADRV9009 收发器进行测量表明,当使用低噪声LO时,可显著改善相位噪声。从相位噪声贡献角度来分析收发器架构。通过一系列测量,残余或加性相位噪声被提取为在DAC输出编程的频率的函数。利用该噪声贡献以及LO和参考电压输入频率的相位噪声,可估计出发射输出的总相位噪声。将这些估计值与测得的结果进行比较。 动机 相位噪声是无线电设计中表征信号质量的重要指标之一。 在架构定义阶段需要进行大量工作,确保以经济的方式满足相位噪声需求。 通过分析ADRV9009收发器的测量结果,其噪声性能结果却决于所选架构,不同架构结果差异较大。使用内部LO功能时,相位噪声由IC内部的锁相环(PLL)和压控振荡器(VCO)决定。内部LO在设计上能满足大多数通信应用的需求。对于需要改进相位噪声的应用,将低相位噪声源作为外部LO时,可显著改进相位噪声。 如图1所示,ADRV9009收发器在10 kHz至100 kHz频段相位噪声改善超过40 dB。以上测量的条件为:对于内部LO测量,LO频率设置为2.6 GHz, DAC输出为8 MHz。对于外部LO测量,Rohde & SchwarzSMA100B用作LO源。由于外部LO信号需要经过ADRV9009的内部分频器,因此为获得2.6 GHz的LO频率,信号源设置为5.2 GHz。使用Holzworth HA7402相位噪声分析仪进行相位噪声的测量。 图1. ADRV9009收发器相位噪声测量。使用内部LO时,相位噪声受到IC内部PLL/VCO的限制。如果使用低相位噪声外部LO,可显著改进相位噪声。 ADRV9009收发器 ADRV9009是ADI收发器产品线的新产品。 收发器架构如图2所示。 该芯片使用直接变频架构,将发射和接收双通道收发链路集成在单芯片中。 其中包含正交校正、直流失调和LO泄漏校正等数字处理算法,这些算法保证了直接变频架构的性能。 收发器提供了射频(RF)与数字之间转换的完整功能。 支持高达6GHz的RF频率,JESD204B接口则为基于ASIC或FPGA的处理器提供高速数据接口。 图2. ADRV9009收发器功能框图。 无线电与外部输入的参考频率同步。转换器时钟、LO和数字时钟的PLL均会与参考时钟锁相。通过外部LO的配置可以绕过内部LO PLL。LO路径的PLL或外部LO输入与混频器端口之间有一个分频器,用于生成直接变频架构所需的正交LO信号。转换器时钟和LO会直接影响相位噪声,在评估相位噪声贡献因素时我们会对此进行进一步讨论。 检查相位噪声贡献因素 发射的相位噪声由多个因素组成。 图3阐明了使用直接变频波形发生器架构的简单功能框图以及主要相位噪声因素。 图3. 直接上变频功能框图和关联相位噪声贡献因素。 在倍频器或分频器中,相位噪声的比例为20logN,其中N是输入输出频率比。 这比例也适用于直接数字频率合成器(DDS),其中时钟噪声贡献与DDS输出频率的比例为20logN。 要考虑的第二个方面是PLL中的相位噪声传递函数,注入PLL的基准频率将作为频率比例函数(类似于倍频器)按比例分配到输出,但会受环路带宽(BW)和所选的环路滤波器所形成的低通滤波器影响。 将这些原则应用于收发器,可检查各种噪声因素的贡献。注入收发器的频率有两种,即LO频率和基准频率。LO频率直接影响相位噪声输出,但在用于创建混频器正交LO信号的内部分频器中减少了6 dB。基准频率贡献由几个因素决定。它用于在时钟PLL中创建DAC时钟。时钟输出上由于基准频率而产生的噪声将与PLL的噪声传递函数成比例。然后,这种噪声贡献再次与DAC时钟与DAC输出频率比成比例。这种效果可以简化为基准频率和DAC输出频率的比例,并受PLL BW低通传递函数影响。 接下来,考虑收发器相位噪声贡献。在发射路径中,所有电路元件都会产生残余噪声,另一个噪声贡献是DAC输出的加性噪声,它随DAC输出频率而变化。这可以总结为两个残余相位噪声术语:频率相关噪声贡献和频率无关噪声贡献。频率相关噪声与DAC输出频率的比例为20logN。频率无关噪声是固定的,将作为收发器的相位噪底。 为了提取IC残余噪声贡献作为频率相关贡献因素和频率无关贡献因素的函数进行了一系列相位噪声测量,如图4所示。 (a). The Reference Frequency and LO Frequency. (b). The Transceiver Transmit Output Phase Noise. (c). The Transceiver Residual Phase Noise. 图4. 用于提取可变相位噪声贡献因素的相位噪声测量。 用于相位噪声测量的测试设置如图5所示。对于收发器LO和基准频率输入,分别使用了Rohde & Schwarz SMA100B和100 A。Holzworth HA7402C用作相位噪声测试设置。对于绝对相位噪声测量,将收发器的发射输出注入测试设置。对于残余相位噪声测量,需要三个收发器,并且将额外的收发器作为测试设置中混频器的LO端口,可从测量中去除基准频率和LO频率的噪声贡献。 (a). Absolute Phase Noise Measurement. (b). Residual Phase Noise Measurement. 图5. 用于相位噪声测量的测试设置。 通过评估图4的实测数据,从收发器IC中提取了频率相关和频率无关相位噪声贡献因素。估计值如图6所示。估计值来自于对实测数据的拟合结果以及在偏移频率大于1 MHz时对相位噪底应用的阈值设置。 图6. 收发器残余相位噪声贡献。这些曲线是从图4的实测数据中提取出来的。 绝对相位噪声测量和预测 如前所述通过评估不同相位噪声贡献,基于DAC输出频率以及用于参考和本振的振荡源,相位噪声可以通过计算预测。 实测和预测结果如图7所示。 (a). DAC Ouput = 12.5 MHz. (b). DAC Output = 25 MHz. (c). DAC Output = 50 MHz. (d). DAC Output = 100 MHz. 图7. 外部LO的测量相位噪声与预测相位噪声的对比。对于2.6…