【圣光之城网站源码】【收银网站系统源码】【妄想山海 辅助源码】细粒度源码_细粒度视频

时间:2024-12-28 09:37:00 来源:rust源码阅读 分类:娱乐

1.代码拆分-使用SplitChunks
2.Rematch 源码系列四、细粒Third-Party plugins
3.[stl 源码分析] std::sort
4.ribbon负载均衡详解
5.Ray 源码解析(一):任务的度源状态转移和组织形式
6.如何使用oprofile对软件做profiling

细粒度源码_细粒度视频

代码拆分-使用SplitChunks

       前言

       探索代码优化的世界,最近开始接触项目优化工作,码细其中涉及三方组件的粒度拆分。在未进行拆分前,视频可能存在两个场景:单一js文件过大,细粒圣光之城网站源码影响缓存效率;无法有效管理第三方库。度源利用`splitChunks`工具,码细可以将模块进行分割,粒度并提取重复代码,视频解决上述问题。细粒

       概念区分 - module、度源bundle、码细chunk

       深入理解`splitChunks`之前,粒度先梳理几个概念。视频module:模块,在webpack中,任何文件都可视为模块,需要配置loader将其转换为支持打包的文件。chunk:编译完成待输出时,webpack将module按特定规则组合成一个个chunk。bundle:webpack处理完chunk文件后,生成供浏览器运行的收银网站系统源码代码。

       chunk与bundle的关系

       探析chunk的构成与bundle之间的关联。chunk有两种形式:初始化(initial)chunk,即入口起点的主chunk,包含入口起点及其依赖的所有模块;非初始化(non-initial)chunk,用于延迟加载,可能在使用动态导入或`SplitChunksPlugin`时出现。

       通过入口产生的chunk

       假设目录结构如下:index.js, another-module.js, webpack.config.js, package.json添加script配置,运行webpack并使用ndb追踪代码执行。通过命令启动浏览器,点击播放按钮执行build命令,追踪chunk到bundle的流转。

       chunk处理步骤概览

       从`Compilation`类的`seal`方法出发,首先搜集chunks,然后调用`createChunkAssets`方法生成source,为输出文件做准备;通过`compilation.emitAssets`方法记录资源信息到`compilation.assets`对象;一系列回调最终调用`onCompiled`方法,将assets信息写入输出目录,生成bundle文件。

       Demo2 - 动态导入

       将`index.js`中的lodash通过`import`方式导入,动态导入返回promise,通过`then`获取导入信息。修改`webpack.config.js`入口为单个`index.js`。源码追踪显示,妄想山海 辅助源码初始化文件新增一个名为`index`的chunk,但在模块分析中识别到`import`方式,为`index.js`模块增加了`AsyncDependenciesBlock`标记,经过处理生成一个名为`null`的chunk。

       总结:`chunk`是源代码中的抽象,封装定义如何将模块组写入文件,而`bundle`则是输出目录的文件。

       解决隐患 - `splitChunks`配置

       在上述示例中,存在三方模块重复引用的问题。通过简单的`optimization.splitChunks`配置,实现了lodash的抽离,降低了单个入口文件的大小。总结使用心得,`splitChunks`主要用于代码优化,针对不同场景配置`chunks`选项,如`all`、`async`、`initial`以及自定义函数,以达到高效拆分效果。

       比较`async`、`initial`、`all`的营销系统模板源码区别

       在示例中增加`another.js`,静态导入lodash,对比`async`、`all`、`initial`的不同效果。默认情况下,`initial`影响HTML文件中的脚本标签,而`async`仅针对动态导入,`all`则考虑更多场景,适合存在复用模块的情况,但需权衡动态导入及其内部依赖的抽离。

       splitChunks.cacheGroups

       在使用`splitChunks`基础上,通过`cacheGroups`实现更细粒度的代码拆分,进一步优化项目结构。

       总结

       通过`splitChunks`配置,实现三方组件的高效管理与拆分,优化代码结构与加载效率。理解模块、bundle、chunk之间的关系,以及如何利用`splitChunks`与`cacheGroups`进行代码拆分与优化,是提升项目性能的关键步骤。

Rematch 源码系列四、antd5源码Third-Party plugins

       本文深入探讨了rematch的两个常用第三方插件:immer与loading。immer插件旨在简化state的修改过程,通过引入immerjs,允许开发者在reducer中使用mutable状态,进而生成immutable状态,简化了常规操作。immer插件的实现相对简单,只需将常规reducer包裹一层,使之通过immerjs处理即可。

       immer插件的核心在于其对reducer的封装,通过immer.produce方法处理draft状态,简化了mutable状态的管理,避免了复杂的clone和赋值操作。当状态为简单数据类型时,不会使用immer.produce,以保持代码的简洁性。更多关于immer.produce和combineReducers的使用和原理可参考官方文档。

       然而,immer插件的设计存在缺陷,即许多reducer配置若不能以数组形式存储,而是被替换,则可能导致插件配置失效。rematch v2版本通过引入更细粒度的plugin hooks(如onReducer)解决了这一问题,提升了配置的灵活性。

       紧接着是loading插件,专注于管理异步操作的状态,包括网络请求等。其核心在于onModel钩子的使用,定义了全局和模型级别的loading状态,并为特定操作定义了show和hide两个reducer,动态跟踪和控制加载状态。

       loading插件的实现通过初始化代码定义了全局和模型级别的loading状态,并使用onModel钩子处理模型操作,对特定的effect动作进行管理,包装原始动作以实现状态控制。两个reducer,show和hide,分别用于增加和减少操作状态的计数,以此实现对加载状态的动态更新。

       本文综述了rematch的immer和loading插件的实现原理、使用场景及优化策略,为开发者提供了深入理解这些工具的框架。后续文章将探讨rematch v1升级到v2的设计变化以及TypeScript支持的实现,期待与开发者共同探索rematch的最新进展和优化。

[stl 源码分析] std::sort

       std::sort在标准库中是一个经典的复合排序算法,结合了插入排序、快速排序、堆排序的优点。该算法在排序时根据几种算法的优缺点进行整合,形成一种被称为内省排序的高效排序方法。

       内省排序结合了快速排序和堆排序的优点,快速排序在大部分情况下具有较高的效率,堆排序在最坏情况下仍能保持良好的性能。内省排序在排序过程中,先用快速排序进行大体排序,然后递归地对未排序部分进行更细粒度的排序,直至完成整个排序过程。在快速排序效率较低时,内省排序会自动切换至插入排序,以提高排序效率。

       在实现上,std::sort使用了内省排序算法,并在适当条件下切换至插入排序以优化性能。其源码包括排序逻辑的实现和测试案例。排序源码主要由内省排序和插入排序两部分组成。

       内省排序在排序过程中先快速排序,然后对未完全排序的元素进行递归快速排序。当子数组的长度小于某个阈值时,内省排序会自动切换至插入排序。插入排序在小规模数据中具有较高的效率,因此在内省排序中作为优化部分,提高了整个排序算法的性能。

       插入排序在排序过程中,将新元素插入已排序部分的正确位置。这种简单而直观的算法在小型数据集或接近排序状态的数据中表现出色。内省排序通过将插入排序应用于小规模数据,进一步优化了排序算法的性能。

       综上所述,std::sort通过结合内省排序和插入排序,实现了高效且稳定的数据排序。内省排序在大部分情况下提供高性能排序,而在数据规模较小或接近排序状态时,插入排序作为优化部分,进一步提高了排序效率。这种复合排序方法使得std::sort成为标准库中一个强大且灵活的排序工具。

ribbon负载均衡详解

       æœåŠ¡ç«¯è´Ÿè½½å‡è¡¡ï¼šåœ¨å®¢æˆ·ç«¯å’ŒæœåŠ¡ç«¯ä¸­é—´ä½¿ç”¨ä»£ç†ï¼Œlvs  和 nginx。

        硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个下挂可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(比如线性轮询、按权重负载、按流量负载等)从维护的可用服务端清单中取出一台服务端端地址,然后进行转发。

        客户端负载均衡:根据自己的情况做负载。Ribbon。

        客户端负载均衡和服务端负载均衡最大的区别在于 服务端地址列表的存储位置,以及负载算法在哪里。

        2、Spring Cloud的负载均衡机制的实现

        Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Ribbon实现客户端的负载均衡,负载均衡器提供很多对.netflix.client.conf.CommonClientConfigKey。

        <clientName>.<nameSpace>.NFLoadBalancerClassName=xx

        <clientName>.<nameSpace>.NFLoadBalancerRuleClassName=xx

        <clientName>.<nameSpace>.NFLoadBalancerPingClassName=xx

        <clientName>.<nameSpace>.NIWSServerListClassName=xx

        <clientName>.<nameSpace>.NIWSServerListFilterClassName=xx

        com.netflix.client.config.IClientConfig:Ribbon的客户端配置,默认采用com.netflix.client.config.DefaultClientConfigImpl实现。

        com.netflix.loadbalancer.IRule:Ribbon的负载均衡策略,默认采用com.netflix.loadbalancer.ZoneAvoidanceRule实现,该策略能够在多区域环境下选出最佳区域的实例进行访问。

        com.netflix.loadbalancer.IPing:Ribbon的实例检查策略,默认采用com.netflix.loadbalancer.NoOpPing实现,该检查策略是一个特殊的实现,实际上它并不会检查实例是否可用,而是始终返回true,默认认为所有服务实例都是可用的。

        com.netflix.loadbalancer.ServerList:服务实例清单的维护机制,默认采用com.netflix.loadbalancer.ConfigurationBasedServerList实现。

        com.netflix.loadbalancer.ServerListFilter:服务实例清单过滤机制,默认采org.springframework.cloud.netflix.ribbon.ZonePreferenceServerListFilter,该策略能够优先过滤出与请求方处于同区域的服务实例。

        com.netflix.loadbalancer.ILoadBalancer:负载均衡器,默认采用com.netflix.loadbalancer.ZoneAwareLoadBalancer实现,它具备了区域感知的能力。

        上面的配置是在项目中没有引入spring Cloud Eureka,如果引入了Eureka和Ribbon依赖时,自动化配置会有一些不同。

        通过自动化配置的实现,可以轻松的实现客户端的负载均衡。同时,针对一些个性化需求,我们可以方便的替换上面的这些默认实现,只需要在springboot应用中创建对应的实现实例就能覆盖这些默认的配置实现。

        @Configuration

        public class MyRibbonConfiguration {

            @Bean

            public IRule ribbonRule(){

                return new RandomRule();

            }

        }

        这样就会使用P使用了RandomRule实例替代了默认的com.netflix.loadbalancer.ZoneAvoidanceRule。

        也可以使用@RibbonClient注解实现更细粒度的客户端配置

       å¯¹äºŽRibbon的参数通常有二种方式:全局配置以及指定客户端配置

        全局配置的方式很简单

        只需要使用ribbon.<key>=<value>格式进行配置即可。其中,<key>代表了Ribbon客户端配置的参数名,<value>则代表了对应参数的值。比如,我们可以想下面这样配置Ribbon的超时时间

        ribbon.ConnectTimeout=

        ribbon.ServerListRefreshInterval=   ribbon获取服务定时时间

        全局配置可以作为默认值进行设置,当指定客户端配置了相应的key的值时,将覆盖全局配置的内容

        指定客户端的配置方式

        <client>.ribbon.<key>=<value>的格式进行配置.<client>表示服务名,比如没有服务治理框架的时候(如Eureka),我们需要指定实例清单,可以指定服务名来做详细的配置,

        user-service.ribbon.listOfServers=localhost:,localhost:,localhost:

        对于Ribbon参数的key以及value类型的定义,可以通过查看com.netflix.client.config.CommonClientConfigKey类。

        当在spring Cloud的应用同时引入Spring cloud Ribbon和Spring Cloud Eureka依赖时,会触发Eureka中实现的对Ribbon的自动化配置。这时的serverList的维护机制实现将被com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList的实例所覆盖,该实现会讲服务清单列表交给Eureka的服务治理机制来进行维护。IPing的实现将被com.netflix.niws.loadbalancer.NIWSDiscoveryPing的实例所覆盖,该实例也将实例接口的任务交给了服务治理框架来进行维护。默认情况下,用于获取实例请求的ServerList接口实现将采用Spring Cloud Eureka中封装的org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList,其目的是为了让实例维护策略更加通用,所以将使用物理元数据来进行负载均衡,而不是使用原生的AWS AMI元数据。在与Spring cloud Eureka结合使用的时候,不需要再去指定类似的user-service.ribbon.listOfServers的参数来指定具体的服务实例清单,因为Eureka将会为我们维护所有服务的实例清单,而对于Ribbon的参数配置,我们依然可以采用之前的两种配置方式来实现。

        此外,由于spring Cloud Ribbon默认实现了区域亲和策略,所以,可以通过Eureka实例的元数据配置来实现区域化的实例配置方案。比如可以将不同机房的实例配置成不同的区域值,作为跨区域的容器机制实现。而实现也非常简单,只需要服务实例的元数据中增加zone参数来指定自己所在的区域,比如:

        eureka.instance.metadataMap.zone=shanghai

        在Spring Cloud Ribbon与Spring Cloud Eureka结合的工程中,我们可以通过参数禁用Eureka对Ribbon服务实例的维护实现。这时又需要自己去维护服务实例列表了。

        ribbon.eureka.enabled=false.

        由于Spring Cloud Eureka实现的服务治理机制强调了cap原理的ap机制(即可用性和可靠性),与zookeeper这类强调cp(一致性,可靠性)服务质量框架最大的区别就是,Eureka为了实现更高的服务可用性,牺牲了一定的一致性,在极端情况下宁愿接受故障实例也不要丢弃"健康"实例。

        比如说,当服务注册中心的网络发生故障断开时候,由于所有的服务实例无法维护续约心跳,在强调ap的服务治理中将会把所有服务实例剔除掉,而Eureka则会因为超过%的实例丢失心跳而触发保护机制,注册中心将会保留此时的所有节点,以实现服务间依然可以进行互相调用的场景,即使其中有部分故障节点,但这样做可以继续保障大多数服务的正常消费。

        在Camden版本,整合了spring retry来增强RestTemplate的重试能力,对于我们开发者来说,只需要简单配置,即可完成重试策略。

        spring.cloud.loadbalancer.retry.enabled=true

        hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=

        user-service.ribbon.ConnectTimeout=

        user-service.ribbon.ReadTimeout=

        user-service.ribbon.OkToRetryOnAllOperations=true

        user-service.ribbon.MaxAutoRetriesNextServer=2

        user-service.ribbon.maxAutoRetries=1

        spring.cloud.loadbalancer.retry.enabled:该参数用来开启重试机制,它默认是关闭的。

        hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:断路器的超时时间需要大于Ribbon的超时时间,不然不会触发重试。

        user-service.ribbon.ConnectTimeout:请求连接超时时间。

        user-service.ribbon.ReadTimeout:请求处理的超时时间

        user-service.ribbon.OkToRetryOnAllOperations:对所有操作请求都进行重试。

        user-service.ribbon.MaxAutoRetriesNextServer:切换实例的重试次数。

        user-service.ribbon.maxAutoRetries:对当前实例的重试次数。

        根据以上配置,当访问到故障请求的时候,它会再尝试访问一次当前实例(次数由maxAutoRetries配置),如果不行,就换一个实例进行访问,如果还是不行,再换一个实例访问(更换次数由MaxAutoRetriesNextServer配置),如果依然不行,返回失败

       é¡¹ç›®å¯åŠ¨çš„时候会自动的为我们加载LoadBalancerAutoConfiguration自动配置类,该自动配置类初始化条件是要求classpath必须要有RestTemplate这个类,必须要有LoadBalancerClient实现类。

        LoadBalancerAutoConfiguration为我们干了二件事,第一件是创建了LoadBalancerInterceptor拦截器bean,用于实现对客户端发起请求时进行拦截,以实现客户端负载均衡。创建了一个

        RestTemplateCustomizer的bean,用于给RestTemplate增加LoadBalancerInterceptor拦截器。

        每次请求的时候都会执行org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor的intercept方法,而LoadBalancerInterceptor具有LoadBalancerClient(客户端负载客户端)实例的一个引用,

        在拦截器中通过方法获取服务名的请求url(比如/p/1bddb5dc

        Spring cloud系列六 Ribbon的功能概述、主要组件和属性文件配置  

       /p/faffa

        本人有道云笔记中记录的参考文章

        文档:_ribbon 负载均衡.note

        链接:/noteshare?id=efc3efbbefd8ed0b9&sub=B0E6DFEEBDAF

Ray 源码解析(一):任务的状态转移和组织形式

       Ray源码解析系列的第一篇着重于任务的状态管理和组织形式。Ray的核心设计在于其细粒度、高吞吐的任务调度,依赖于共享内存的Plasma存储输入和输出,以及Redis的GCS来管理所有状态,实现去中心化的调度。任务分为无状态的Task和有状态的Actor Method,后者包括Actor的构造函数和成员函数。

       Ray支持显式指定任务的资源约束,通过ResourcesSet量化节点资源,用于分配和回收。在调度时,需找到满足任务资源要求的节点。由于Task输入在分布式存储中,调度后需要传输依赖。对于Actor Method,其与Actor绑定,会直接调度到对应的节点。

       状态变化如任务状态转移、资源依赖等信息,都存储在GCS中。任务状态更改需更新GCS,失联或宕机时,根据GCS中的状态信息重试任务。通过GCS事件订阅驱动任务状态变化。

       文章主要讲述了任务状态的组织方式,如任务队列(TaskQueue)和调度队列(SchedulingQueue)的运作,以及状态转移图和状态枚举类的定义。例如,TaskQueue负责任务的增删查改,其中ReadyQueue通过资源映射优化调度决策。此外,文中还解释了一些关键概念,如Task Required Resources、Task argument、Object、Object Store、Node/Machine等。

       后续文章将深入探讨调度策略和资源管理。让我们期待下篇的精彩内容。

如何使用oprofile对软件做profiling

       ã€€ã€€å…³äºŽXilinx Zynq-带来的新的系统设计思路,以及Profiling的对象libjpeg,前文已经描述过了,再此不再赘述。

       ã€€ã€€ä¸€. Oprofile简介

       ã€€ã€€Profiling是对不同性能特征的数据的形式化总结或分析,它通常以图形和表的形式出现。它提供为特定的处理器事件收集的采样百分数或数 量,比如cache miss rate、TLB miss rate等等。一般来说,主要目的是为了找出软件中的性能瓶颈,然后有针对性的优化以提升软件的整体性能。

       ã€€ã€€Oprofile 是用于 Linux 的若干种评测和性能监控工具中的一种。它可以工作在不同的体系结构上,包括ARM, PowerPC, MIPS, IA, IA 和 AMD Athlon等等。它的开销很小,从Linux 2.6 版起,它被包含进了Linux内核中。

       ã€€ã€€Oprofile可以收集有关处理器事件的信息,帮助用户识别诸如循环的展开、cache的使用率低、低效的类型转换和冗余操作、错误预测转移 等问题。Oprofile是一种细粒度的工具,可以为指令集或者为函数、系统调用或中断处理例程收集采样。Oprofile 通过取样来工作。使用收集到的评测数据,用户可以很容易地找出性能问题。

       ã€€ã€€é€šè¿‡ç›‘察CPU的hardware events,oprofile可以在运行状态下对整个Linux系统进行profiling。Profiling的对象可以是Linux kernel (包括modules和interrupt handlers), shared libraries或者应用程序。

       ã€€ã€€ä»Ž0.9.8版本开始,oprofile支持Perf_events profiling mode模式。应用程序operf被用来控制profiling过程;而在legacy mode下,是通过opcontrol脚本和oprofiled daemon来完成的。Operf不再象legacy mode那样需要OProfile kernel driver,它直接和Linux Kernel Performance Events Subsystem打交道。使用operf,就可以用普通用户的身份来profiling用户的应用程序了,当然如果需要对整个系统来profiling 的时候还是需要root权限的。

       ã€€ã€€å¦‚果硬件不支持OProfile使用performance counters,OProfile就只能工作在Timer Mode下了。Timer Mode只能在legacy profiling mode下使用,即只能通过opcontrol脚本来控制。

       ã€€ã€€Oprofile的website为:piled (JIT) code

       ã€€ã€€? 可以对整个系统做profiling

       ã€€ã€€? 可以观察CPU内部的细节,例如cache miss rate

       ã€€ã€€? 可以多源代码做annotation

       ã€€ã€€? 可以支持instruction-level的profiling

       ã€€ã€€? 可以生成call-graph profiles

       ã€€ã€€ä¸è¿‡OProfile也不是万能的,它也有自己的局限性:

       ã€€ã€€? 只能在x, ARM, 和PowerPC架构上生成call graph profiles

       ã€€ã€€? 不支持%精确的instruction-level profiling

       ã€€ã€€? 对dynamically compiled (JIT) code profiling的支持还不完善。

       ã€€ã€€æ— è®ºå¦‚何,Oprofile的功能都比gprof要强很多,代价是配置起来会比较麻烦。

       ã€€ã€€äºŒ. 编译Oprofile

       ã€€ã€€é¦–先最好在Linux kernel里面选中Oprofile driver,以获得全面的支持。

       ã€€ã€€ä¸‹è½½Linux kernel Source:从/Xilinx/linux-xlnx 可以下载到Xilinx提供的验证好的内核。如果不方便使用Linux下的git工具,可以单击页面上的releases找到相应的版本下载tar ball。下载的时候最好选tar.gz格式的,而不是zip格式的,因为后者在处理symbol link的时候有可能会出问题。

       ã€€ã€€å› ä¸ºç¬”者使用的是Xilinx Linux pre-built .7,所以这里下载的是linux-xlnx-xilinx-v.7.tar.gz

       ã€€ã€€è§£åŽ‹ç¼©åŽï¼Œç”¨ä»¥ä¸‹å‘½ä»¤è°ƒå‡ºLinux kernel的配置界面:

       ã€€ã€€export ARCH=arm

       ã€€ã€€export CROSS_COMPILE=arm-xilinx-linux-gnueabi-

       ã€€ã€€make xilinx_zynq_defconfig

       ã€€ã€€make xconfig 或者make menuconfig

       ã€€ã€€åœ¨é…ç½®ç•Œé¢ä¸Šå°†ä»¥ä¸‹ä¸¤é¡¹å‹¾ä¸Šï¼š

       ã€€ã€€General setup --->

       ã€€ã€€[*] Profiling support

       ã€€ã€€<*> OProfile system profiling

       ã€€ã€€ç„¶åŽmake uImage即可生成新的uImage,用来替换Xilinx Linux pre-built .7中的Linux kernel image。同时我们也需要vmlinux来检查profiling的结果。

       ã€€ã€€Oprofile需要popt, bfd, liberty库,要在嵌入式单板上使用这些库,需要手工完成交叉编译。

       ã€€ã€€é’ˆå¯¹popt 1.7,用以下命令完成编译:

       ã€€ã€€./configure --prefix=/home/wave/xilinx/oprofileprj/rootfs --host=arm-xilinx-linux-gnueabi --with-kernel-support --disable-nls && make && make install

       ã€€ã€€é’ˆå¯¹binutils 2.,用以下命令完成编译:

       ã€€ã€€./configure --host=arm-xilinx-linux-gnueabi --prefix=/home/wave/xilinx/oprofileprj/rootfs --enable-install-libbfd --enable-install-libiberty --enable-shared && make && make install

       ã€€ã€€ä¸è¿‡--enable-install-libiberty没有效果,所以需要手工把libiberty.a和libiberty.h拷贝到相应的位置。

       ã€€ã€€é’ˆå¯¹oprofile 0.9.9,用以下命令完成编译:

       ã€€ã€€./configure --host=arm-xilinx-linux-gnueabi --prefix=/home/wave/xilinx/oprofileprj/rootfs --with-kernel-support --with-binutils=/home/wave/xilinx/oprofileprj/rootfs && make && make install

       ã€€ã€€é…ç½®è¿‡ç¨‹ç»“束后可能会有以下提示,因为没有打算用GUI和profile JITed code,所以直接忽视之。

       ã€€ã€€config.status: executing libtool commands

       ã€€ã€€Warning: QT version 3 was requested but not found. No GUI will be built.

       ã€€ã€€Warning: The user account 'oprofile:oprofile' does not exist on the system.

       ã€€ã€€To profile JITed code, this special user account must exist.

       ã€€ã€€Please ask your system administrator to add the following user and group:

       ã€€ã€€user name : 'oprofile'

       ã€€ã€€group name: 'oprofile'

       ã€€ã€€The 'oprofile' group must be the default group for the 'oprofile' user.

       ã€€ã€€å°†ç¼–译完成的uImage,vmlinux,oprofile binary,重新编译的没有-pg的libjpeg binary以及tool chain的libc打包放到SD卡中,准备在ZC开发板上尝试profile djpeg。

       ã€€ã€€ä¸‰. 运行Oprofile

       ã€€ã€€æ­£å¸¸å¯åŠ¨åµŒå…¥å¼Linux后,在开发板的console上一次输入以下命令:

       ã€€ã€€mount /dev/mmcblk0p1 /mnt

       ã€€ã€€mkdir -p /home/root/work

       ã€€ã€€cd /home/root/work

       ã€€ã€€tar zxvf /mnt/jpeg-bin-nopg.tar.gz

       ã€€ã€€cd jpeg-bin/bin

       ã€€ã€€cp /mnt/park-x.jpg .

       ã€€ã€€export LD_LIBRARY_PATH=/home/root/work/jpeg-bin/lib

       ã€€ã€€cd /home/root/work

       ã€€ã€€tar zxvf /mnt/rootfs.tar.gz

       ã€€ã€€cd rootfs

       ã€€ã€€chown root:root -R

*

       ã€€ã€€cp -R bin/* /usr/bin

       ã€€ã€€cp -R lib/* /lib

       ã€€ã€€cp /bin/which /usr/bin

       ã€€ã€€cp /bin/dirname /usr/bin

       ã€€ã€€mkdir -p /home/wave/xilinx/oprofileprj/rootfs/share

       ã€€ã€€cp -R ./rootfs/* /home/wave/xilinx/oprofileprj/rootfs

       ã€€ã€€cd /home/root/work

       ã€€ã€€tar zxvf /mnt/libc.tar.gz

       ã€€ã€€cp ./lib/libstdc*.* /lib

       ã€€ã€€mkdir -p /home/wave/xilinx/libjpeg

       ã€€ã€€cd /home/wave/xilinx/libjpeg

       ã€€ã€€tar zxvf /mnt/jpeg-9.tar.gz

       ã€€ã€€cp /mnt/vmlinux /home/root/work

       ã€€ã€€cd /home/root/work/jpeg-bin/bin

       ã€€ã€€opcontrol --init

       ã€€ã€€opcontrol --vmlinux=/home/root/work/vmlinux

       ã€€ã€€opcontrol --setup --event=CPU_CYCLES:::0:1 --session-dir=/home/root/

       ã€€ã€€operf --vmlinux /home/root/work/vmlinux ./djpeg -bmp park-x.jpg > result.bmp

       ã€€ã€€opreport -l ./djpeg

       ã€€ã€€å®Œæˆè¿™ä¸€æ­¥åŽï¼Œæˆ‘们就可以看到profiling的结果了,在笔者的平台上看到的内容的主要部分如下:

       ã€€ã€€root@zynq:~/work/jpeg-bin/bin# opreport -l ./djpeg

       ã€€ã€€Using /home/root/work/jpeg-bin/bin/oprofile_data/samples/ for samples directory.

       ã€€ã€€CPU: ARM Cortex-A9, speed MHz (estimated)

       ã€€ã€€Counted CPU_CYCLES events (CPU cycle) with a unit mask of 0x (No unit mask) count

       ã€€ã€€samples % image name symbol name

       ã€€ã€€ . libc-2..so /lib/libc-2..so

       ã€€ã€€ 7. libjpeg.so.9.0.0 ycc_rgb_convert

       ã€€ã€€ 7. libjpeg.so.9.0.0 jpeg_idct_x

       ã€€ã€€ 7. libjpeg.so.9.0.0 decode_mcu

       ã€€ã€€ 6. libjpeg.so.9.0.0 jpeg_idct_islow

       ã€€ã€€ 6. djpeg finish_output_bmp

       ã€€ã€€ 2. libjpeg.so.9.0.0 jpeg_fill_bit_buffer

       ã€€ã€€ 1. djpeg put_pixel_rows

       ã€€ã€€ 0. vmlinux __copy_from_user

       ã€€ã€€ 0. libjpeg.so.9.0.0 decompress_onepass

       ã€€ã€€ 0. libjpeg.so.9.0.0 jpeg_huff_decode

       ã€€ã€€ 0. vmlinux get_page_from_freelist

       ã€€ã€€ 0. vmlinux __memzero

       ã€€ã€€ 0. vmlinux __copy_to_user_std

       ã€€ã€€ 0. vmlinux _raw_spin_unlock_irqrestore

       ã€€ã€€ 0. vmlinux do_page_fault

       ã€€ã€€ 0. vmlinux __generic_file_aio_write

       ã€€ã€€ 0. vmlinux _raw_spin_unlock_irq

       ã€€ã€€ 0. vmlinux free_hot_cold_page

       ã€€ã€€ 0. vmlinux vector_swi

       ã€€ã€€ 0. vmlinux handle_pte_fault

       ã€€ã€€ä»Žç»“果中我们可以看到libjpeg.so.9.0.0, djpeg和vmlinux中的symbol name已经可以被正确的解析出来了,和gprof的结果基本一致。相比gprof,oprofile可以在更大的范围内完成profiling。

       ã€€ã€€æˆ‘们还可以用以下命令观察源代码中特定行的执行时间,进一步缩小优化的范围,达到事半功倍的效果。

       ã€€ã€€opannotate --source ./djpeg > opannotate.txt

       ã€€ã€€å››. 小结

       ã€€ã€€é€šè¿‡å®žéªŒï¼Œæˆ‘们可以看到Oprofile可以提供更丰富的profiling结果,可以更好的帮助开发者找到瓶颈,通过有针对性的优化提升软件 性能;profiling的结果也可以帮助开发者将性能瓶颈代码通过Xilinx HLS工具用硬件加速器来实现,从而为进一步提升整个嵌入式系统的性能打开了大门。