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`。源码追踪显示,PA源码是什么初始化文件新增一个名为`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 源码系列四、精品买卖公式源码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å·¥å ·ç¨ç¡¬ä»¶å éå¨æ¥å®ç°ï¼ä»è为è¿ä¸æ¥æåæ´ä¸ªåµå ¥å¼ç³»ç»çæ§è½æå¼äºå¤§é¨ã