├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── conf.json ├── dataset ├── soc_model │ ├── README.md │ ├── model_e7420.json │ ├── model_e8890.json │ ├── model_e8895.json │ ├── model_sdm616.json │ ├── model_sdm625.json │ ├── model_sdm626.json │ ├── model_sdm636.json │ ├── model_sdm650_652_653.json │ ├── model_sdm660.json │ ├── model_sdm820.json │ ├── model_sdm821_v1.json │ ├── model_sdm821_v2.json │ ├── model_sdm821_v3.json │ ├── model_sdm835.json │ └── raw │ │ ├── e7420.xlsx │ │ ├── e8890.xlsx │ │ ├── e8895.xlsx │ │ ├── sd626.xlsx │ │ ├── sd820.xlsx │ │ ├── sd821.xlsx │ │ ├── sd835.xlsx │ │ ├── sdm616.xlsx │ │ ├── sdm636.xlsx │ │ ├── sdm650.xlsx │ │ └── sdm660.csv └── workload │ └── osborn │ ├── bili-danmu.json │ ├── bili-download.json │ ├── bili-feed.json │ ├── coolapk-feed.json │ ├── game-7days-city-boss.json │ ├── game-7days-city-regular.json │ ├── idle-music.json │ ├── meituan-explore.json │ ├── offscreen-merged.json │ ├── onscreen-merged.json │ ├── qq-chat.json │ ├── qq-qzone.json │ ├── raw │ ├── README.md │ └── info.json │ ├── share-feed.json │ ├── taobao-international-explore.json │ ├── task-switch.json │ ├── tieba-lite.json │ ├── twitter-feed.json │ ├── via-iphonexs-intro.json │ ├── wx-chat.json │ ├── wx-gongzhonghao.json │ ├── wx-moment.json │ ├── wx-select-pic.json │ └── xianyu-search.json ├── media └── sim.png ├── source ├── 3rd │ ├── nlohmann │ │ └── json.hpp │ └── openga │ │ └── openga.hpp ├── main.cpp ├── opt │ ├── openga_helper.cpp │ └── openga_helper.h ├── output │ ├── dump.cpp │ └── dump.h ├── sim │ ├── cpumodel.cpp │ ├── cpumodel.h │ ├── hmp.h │ ├── hmp_pelt.cpp │ ├── hmp_pelt.h │ ├── hmp_walt.cpp │ ├── hmp_walt.h │ ├── input_boost.cpp │ ├── input_boost.h │ ├── interactive.cpp │ ├── interactive.h │ ├── rank.cpp │ ├── rank.h │ ├── sim.hpp │ ├── sim_types.h │ ├── workload.cpp │ └── workload.h └── utils │ └── misc.h ├── template └── powercfg_template.sh └── tools ├── migrate.py ├── standby_load_20180308_from_171023.csv └── tracefile_parse.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # too big ADB systrace, ~600MB 35 | *.html 36 | 37 | # binary 38 | /wipe 39 | 40 | /.vscode 41 | /build 42 | /output 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Project WIPE-v2 2 | # Author: Matt Yang 3 | 4 | CC := gcc 5 | CXX := g++ 6 | CFLAGS := -std=c99 -flto 7 | CXXFLAGS := -std=c++11 -flto 8 | LDFLAGS := -Wl,--as-needed -flto 9 | 10 | SRC_DIR := ./source 11 | INC_DIR := ./source 12 | BUILD_DIR := ./build 13 | DEP_DIR := $(BUILD_DIR)/dep 14 | 15 | BIN_NAME := wipe 16 | REL_FLAGS := -O3 -s 17 | REL_DEFINES := 18 | DBG_FLAGS := -O0 -g -Wall 19 | DBG_DEFINES := 20 | 21 | EXT_LIB_INC := 22 | EXT_LIBS := 23 | 24 | INC := $(shell find $(INC_DIR) -name '*.h') 25 | INC += $(shell find $(INC_DIR) -name '*.hpp') 26 | SRC := $(shell find $(SRC_DIR) -name '*.c') 27 | SRC += $(shell find $(SRC_DIR) -name '*.cpp') 28 | 29 | OBJS := $(foreach f,$(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SRC))),$(BUILD_DIR)/$(f)) 30 | INCLUDES := $(foreach f,$(sort $(dir $(INC))),-I$(f)) $(EXT_LIB_INC) 31 | LIBS := -lpthread $(EXT_LIBS) 32 | 33 | # 生成.c/cpp对.h的依赖,由include插入到makefile, 不使用冒号用于延后展开 $@ 和 $(*F) 34 | # http://maskray.me/blog/2011-08-11-generate-dependency-in-makefile 35 | DEP_FLAGS = -MM -MP -MT $@ -MF $(DEP_DIR)/$(*F).d 36 | 37 | # gcc并不会自己生成目录 38 | $(shell mkdir -p $(DEP_DIR) > /dev/null) 39 | $(shell mkdir -p $(dir $(OBJS)) > /dev/null) 40 | 41 | .PHONY: all release debug clean help 42 | 43 | all: release 44 | 45 | release: MODE_FLAG = $(REL_FLAGS) 46 | release: DEFINES = $(REL_DEFINES) 47 | release: $(OBJS) 48 | @$(CXX) $(CXXFLAGS) $(INCLUDES) $(LDFLAGS) $(DEFINES) $(MODE_FLAG) -o $(BIN_NAME) $^ $(LIBS) 49 | @echo -e ' bin\t ./$(BIN_NAME)' 50 | @echo -e '\033[32m\033[1m build $@ done. \033[0m' 51 | 52 | debug: MODE_FLAG = $(DBG_FLAGS) 53 | debug: DEFINES = $(DBG_DEFINES) 54 | debug: $(OBJS) 55 | @$(CXX) $(CXXFLAGS) $(INCLUDES) $(LDFLAGS) $(DEFINES) $(MODE_FLAG) -o $(BIN_NAME) $^ $(LIBS) 56 | @echo -e ' bin\t ./$(BIN_NAME)' 57 | @echo -e '\033[32m\033[1m build $@ done. \033[0m' 58 | 59 | $(BUILD_DIR)/%.o: %.c 60 | @echo -e ' cc\t $<' 61 | @$(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) $(MODE_FLAG) $(DEP_FLAGS) $< 62 | @$(CC) $(CFLAGS) $(INCLUDES) $(DEFINES) $(MODE_FLAG) -c $< -o $@ 63 | 64 | $(BUILD_DIR)/%.o: %.cpp 65 | @echo -e ' cxx\t $<' 66 | @$(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) $(MODE_FLAG) $(DEP_FLAGS) $< 67 | @$(CXX) $(CXXFLAGS) $(INCLUDES) $(DEFINES) $(MODE_FLAG) -c $< -o $@ 68 | 69 | -include $(foreach f,$(notdir $(basename $(SRC))),$(DEP_DIR)/$(f).d) 70 | 71 | clean: 72 | @rm -f $(BIN_NAME) 73 | @rm -rf $(BUILD_DIR) 74 | @echo -e '\033[32m\033[1m clean done. \033[0m' 75 | 76 | help: 77 | @echo -e 'Makefile for Project WIPE-v2' 78 | @echo -e 'Author: Matt Yang' 79 | @echo -e 'make release -j4 \tbuild for actual use' 80 | @echo -e 'make debug -j4 \t\tbuild for development' 81 | @echo -e 'make clean \t\tnecessary when switching between "release" and "debug"' 82 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project WIPE v2 2 | 3 | ![WIPE v2 simulator](media/sim.png) 4 | 5 | ## 设计目标 6 | 7 | 本计划旨在通过制作自动化程序,来优化interactive,HMP,inputboost参数: 8 | This project aims to optimize the parameters of interactive, HMP, and inputboost by creating automated programs: 9 | 10 | - 现实负载采集(real world workload capture) 11 | - interactive调速器流程仿真(interactive governor process simulation) 12 | - 卡顿和耗电评分函数(cost function of lag and power comsuption) 13 | - 迭代取得局部最优(iteration to obtain local optimum) 14 | 15 | 相比[Project WIPE v1](https://github.com/yc9559/cpufreq-interactive-opt/): 16 | 17 | 1. 支持WALT HMP参数模拟 18 | 2. 支持input boost参数模拟 19 | 3. 全频率档位支持及可变参数序列长度 20 | 4. 毫秒级的负载序列和渲染的性能需求,来自systrace 21 | 5. 改进的续航和性能评分函数 22 | 6. 启发式优化算法使用NSGA-III 23 | 7. 同样的任务量和硬件条件下,优化执行效率提升~450% 24 | 25 | ## 如何使用 26 | 27 | 1. 编译发布版本`make release` 28 | 2. 修改配置文件`./conf.json`,选择要做优化的CPU模型列表,以及使用的负载序列和参数范围 29 | 3. 执行`mkdir output`创建输出文件夹 30 | 4. 执行`./wipe`,会自动加载`./conf.json`,并按照列表顺序依次执行优化 31 | 5. 到`output`输出文件夹,根据你的流畅度和耗电的要求,在候选中寻找合适的参数组合 32 | 6. 本项目在GCC 7.3测试通过 33 | 34 | ## 包含的第三方库 35 | 36 | - [nlohmann/json](https://github.com/nlohmann/json) 37 | - [OpenGA](https://github.com/Arash-codedev/openGA) 38 | 39 | ## Credit 40 | 41 | @TSU守望者 42 | -------------------------------------------------------------------------------- /conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wipe v2 配置文件", 3 | "todoModels": [ 4 | "./dataset/soc_model/model_sdm660.json", 5 | "./dataset/soc_model/model_sdm820.json", 6 | "./dataset/soc_model/model_sdm835.json", 7 | "./dataset/soc_model/model_sdm821_v1.json", 8 | "./dataset/soc_model/model_sdm821_v2.json", 9 | "./dataset/soc_model/model_sdm821_v3.json", 10 | "./dataset/soc_model/model_sdm625.json", 11 | "./dataset/soc_model/model_sdm626.json", 12 | "./dataset/soc_model/model_sdm636.json", 13 | "./dataset/soc_model/model_sdm650_652_653.json", 14 | "./dataset/soc_model/model_sdm616.json", 15 | "./dataset/soc_model/model_e8895.json", 16 | "./dataset/soc_model/model_e8890.json", 17 | "./dataset/soc_model/model_e7420.json" 18 | ], 19 | "mergedWorkload": "./dataset/workload/osborn/onscreen-merged.json", 20 | "idleWorkload": "./dataset/workload/osborn/offscreen-merged.json", 21 | "useUperf": true, 22 | "gaParameter": { 23 | "comment": "NSGA3优化算法参数,开启多线程后固定的随机数种子不能带来固定的结果,因为线程访问随机数的顺序不定", 24 | "population": 1536, 25 | "generationMax": 1000, 26 | "crossoverFraction": 0.95, 27 | "mutationRate": 0.05, 28 | "eta": 0.05, 29 | "threadNum": 12, 30 | "randomSeed": 23333 31 | }, 32 | "miscSettings": { 33 | "comment": "亮屏基础功耗400mw 灭屏基础功耗30mw 卡顿评分常规占比1% 卡顿评分渲染掉帧占比99% 卡顿评分使用的分区卡顿计数分区长度为1000 连着卡顿2次认为是连续卡顿 连着卡顿4次认为是严重连续卡顿 连着卡顿至多2次 孤立卡顿权重0.02 连续卡顿权重1.00 严重连续卡顿权重1.00 性能需求大于足够快的性能容量的卡顿权重为0.25 interactive参数复杂度在性能占比4% 续航评分使用的分区耗电计数分区长度为2000 续航评分待机占比1% 续航评分亮屏占比99% 待机续航不低于参考的100% 卡顿比例不超过参考的120%", 34 | "sim.power.workingBase_mw": 400, 35 | "sim.power.idleBase_mw": 30, 36 | "eval.perf.commonFraction": 0.01, 37 | "eval.perf.renderFraction": 0.99, 38 | "eval.perf.partitionLen": 1000, 39 | "eval.perf.seqLagL1": 2, 40 | "eval.perf.seqLagL2": 4, 41 | "eval.perf.seqLagL0Scale": 0.02, 42 | "eval.perf.seqLagL1Scale": 1.00, 43 | "eval.perf.seqLagL2Scale": 1.00, 44 | "eval.perf.seqLagMax": 2, 45 | "eval.perf.enoughPenalty": 0.25, 46 | "eval.power.partitionLen": 2000, 47 | "eval.complexityFraction": 0.02, 48 | "ga.cost.batteryScore.idleFraction": 0.01, 49 | "ga.cost.batteryScore.workFraction": 0.99, 50 | "ga.cost.limit.idleLastingMin": 1.00, 51 | "ga.cost.limit.performanceMax": 1.20 52 | }, 53 | "parameterRange": { 54 | "comment": "interactive, hmp, inputboost 参数优化范围,时长类参数单位为10ms(1个quantum)", 55 | "above_hispeed_delay": { 56 | "min": 1, 57 | "max": 10 58 | }, 59 | "go_hispeed_load": { 60 | "min": 10, 61 | "max": 99 62 | }, 63 | "max_freq_hysteresis": { 64 | "min": 0, 65 | "max": 0 66 | }, 67 | "min_sample_time": { 68 | "min": 1, 69 | "max": 10 70 | }, 71 | "target_loads": { 72 | "min": 1, 73 | "max": 99 74 | }, 75 | "sched_downmigrate": { 76 | "min": 30, 77 | "max": 95 78 | }, 79 | "sched_upmigrate": { 80 | "min": 30, 81 | "max": 95 82 | }, 83 | "sched_ravg_hist_size": { 84 | "min": 5, 85 | "max": 5 86 | }, 87 | "sched_window_stats_policy": { 88 | "min": 2, 89 | "max": 2 90 | }, 91 | "sched_boost": { 92 | "min": 0, 93 | "max": 0 94 | }, 95 | "timer_rate": { 96 | "min": 2, 97 | "max": 2 98 | }, 99 | "input_duration": { 100 | "min": 0, 101 | "max": 300 102 | }, 103 | "load_avg_period_ms": { 104 | "min": 128, 105 | "max": 128 106 | }, 107 | "down_threshold": { 108 | "min": 214, 109 | "max": 214 110 | }, 111 | "up_threshold": { 112 | "min": 524, 113 | "max": 524 114 | }, 115 | "boost": { 116 | "min": 0, 117 | "max": 0 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /dataset/soc_model/README.md: -------------------------------------------------------------------------------- 1 | efficiency: 1024为A53作为基准值 2 | 功耗测试: GPU FLOPS -------------------------------------------------------------------------------- /dataset/soc_model/model_e7420.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e7420", 3 | "device": "三星 S6", 4 | "enoughCapacityPct": 80, 5 | "sched": "pelt", 6 | "intra": "smp", 7 | "inputBoost": false, 8 | "cluster": [ 9 | { 10 | "coreNum": 4, 11 | "efficiency": 1024, 12 | "minFreq": 400, 13 | "maxFreq": 1500, 14 | "opp": [ 15 | 400, 16 | 500, 17 | 600, 18 | 700, 19 | 800, 20 | 900, 21 | 1000, 22 | 1100, 23 | 1200, 24 | 1300, 25 | 1400, 26 | 1500 27 | ], 28 | "corePower": [ 29 | 28, 30 | 37, 31 | 53, 32 | 68, 33 | 84, 34 | 100, 35 | 124, 36 | 148, 37 | 184, 38 | 216, 39 | 256, 40 | 296 41 | ], 42 | "clusterPower": [ 43 | 7, 44 | 9, 45 | 13, 46 | 17, 47 | 21, 48 | 25, 49 | 31, 50 | 37, 51 | 46, 52 | 54, 53 | 64, 54 | 74 55 | ], 56 | "author": "yc9559@酷安", 57 | "comment": "回归估计 https://www.anandtech.com/show/9330/exynos-7420-deep-dive/5" 58 | }, 59 | { 60 | "coreNum": 4, 61 | "efficiency": 1536, 62 | "minFreq": 800, 63 | "maxFreq": 2100, 64 | "opp": [ 65 | 800, 66 | 900, 67 | 1000, 68 | 1100, 69 | 1200, 70 | 1300, 71 | 1400, 72 | 1500, 73 | 1600, 74 | 1700, 75 | 1800, 76 | 1896, 77 | 2000, 78 | 2100 79 | ], 80 | "corePower": [ 81 | 208, 82 | 240, 83 | 264, 84 | 304, 85 | 368, 86 | 416, 87 | 480, 88 | 528, 89 | 624, 90 | 720, 91 | 840, 92 | 992, 93 | 1184, 94 | 1440 95 | ], 96 | "clusterPower": [ 97 | 52, 98 | 60, 99 | 66, 100 | 76, 101 | 92, 102 | 104, 103 | 120, 104 | 132, 105 | 156, 106 | 180, 107 | 210, 108 | 248, 109 | 296, 110 | 360 111 | ], 112 | "author": "yc9559@酷安", 113 | "comment": "回归估计 https://www.anandtech.com/show/9330/exynos-7420-deep-dive/5" 114 | } 115 | ] 116 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_e8890.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e8890", 3 | "device": "三星 S7", 4 | "enoughCapacityPct": 71, 5 | "sched": "pelt", 6 | "intra": "smp", 7 | "inputBoost": false, 8 | "cluster": [ 9 | { 10 | "coreNum": 4, 11 | "efficiency": 1024, 12 | "minFreq": 442, 13 | "maxFreq": 1586, 14 | "opp": [ 15 | 442, 16 | 546, 17 | 754, 18 | 858, 19 | 962, 20 | 1066, 21 | 1170, 22 | 1274, 23 | 1378, 24 | 1482, 25 | 1586 26 | ], 27 | "corePower": [ 28 | 40, 29 | 46, 30 | 58, 31 | 64, 32 | 70, 33 | 78, 34 | 88, 35 | 96, 36 | 110, 37 | 124, 38 | 144 39 | ], 40 | "clusterPower": [ 41 | 10, 42 | 12, 43 | 14, 44 | 16, 45 | 18, 46 | 19, 47 | 22, 48 | 24, 49 | 28, 50 | 31, 51 | 36 52 | ], 53 | "author": "yc9559@酷安", 54 | "comment": "使用骁龙660小核数据线性回归" 55 | }, 56 | { 57 | "coreNum": 4, 58 | "efficiency": 1638, 59 | "minFreq": 728, 60 | "maxFreq": 2600, 61 | "opp": [ 62 | 728, 63 | 832, 64 | 936, 65 | 1040, 66 | 1144, 67 | 1248, 68 | 1352, 69 | 1456, 70 | 1560, 71 | 1664, 72 | 1768, 73 | 1872, 74 | 1976, 75 | 2080, 76 | 2184, 77 | 2288, 78 | 2392, 79 | 2496, 80 | 2600 81 | ], 82 | "corePower": [ 83 | 208, 84 | 256, 85 | 304, 86 | 352, 87 | 408, 88 | 464, 89 | 520, 90 | 576, 91 | 656, 92 | 736, 93 | 832, 94 | 944, 95 | 1072, 96 | 1216, 97 | 1392, 98 | 1592, 99 | 1832, 100 | 2184, 101 | 2672 102 | ], 103 | "clusterPower": [ 104 | 52, 105 | 64, 106 | 76, 107 | 88, 108 | 102, 109 | 116, 110 | 130, 111 | 144, 112 | 164, 113 | 184, 114 | 208, 115 | 236, 116 | 268, 117 | 304, 118 | 348, 119 | 398, 120 | 458, 121 | 546, 122 | 668 123 | ], 124 | "author": "yc9559@酷安", 125 | "comment": "使用i冰宇宙数据估计 https://www.zhihu.com/question/37422042/answer/88962138" 126 | } 127 | ] 128 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_e8895.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e8895", 3 | "device": "三星 S8", 4 | "enoughCapacityPct": 83, 5 | "sched": "pelt", 6 | "intra": "smp", 7 | "inputBoost": false, 8 | "cluster": [ 9 | { 10 | "coreNum": 4, 11 | "efficiency": 1024, 12 | "minFreq": 455, 13 | "maxFreq": 1690, 14 | "opp": [ 15 | 455, 16 | 598, 17 | 715, 18 | 832, 19 | 949, 20 | 1053, 21 | 1248, 22 | 1456, 23 | 1690 24 | ], 25 | "corePower": [ 26 | 78, 27 | 91, 28 | 104, 29 | 114, 30 | 125, 31 | 136, 32 | 158, 33 | 184, 34 | 224 35 | ], 36 | "clusterPower": [ 37 | 19, 38 | 23, 39 | 26, 40 | 28, 41 | 31, 42 | 34, 43 | 40, 44 | 46, 45 | 56 46 | ], 47 | "author": "yc9559@酷安", 48 | "comment": "使用骁龙835小核数据线性回归" 49 | }, 50 | { 51 | "coreNum": 4, 52 | "efficiency": 1664, 53 | "minFreq": 741, 54 | "maxFreq": 2314, 55 | "opp": [ 56 | 741, 57 | 858, 58 | 962, 59 | 1066, 60 | 1170, 61 | 1261, 62 | 1469, 63 | 1703, 64 | 1807, 65 | 1937, 66 | 2002, 67 | 2158, 68 | 2314 69 | ], 70 | "corePower": [ 71 | 196, 72 | 235, 73 | 274, 74 | 313, 75 | 352, 76 | 420, 77 | 548, 78 | 743, 79 | 860, 80 | 1017, 81 | 1056, 82 | 1310, 83 | 1604 84 | ], 85 | "clusterPower": [ 86 | 49, 87 | 59, 88 | 68, 89 | 78, 90 | 88, 91 | 105, 92 | 137, 93 | 186, 94 | 215, 95 | 254, 96 | 264, 97 | 328, 98 | 401 99 | ], 100 | "author": "yc9559@酷安", 101 | "comment": "使用水瓶实测数据线性回归" 102 | } 103 | ] 104 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm616.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm616", 3 | "device": "华为荣耀5x", 4 | "enoughCapacityPct": 89, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": false, 8 | "cluster": [ 9 | { 10 | "coreNum": 4, 11 | "efficiency": 1024, 12 | "minFreq": 200, 13 | "maxFreq": 1209, 14 | "opp": [ 15 | 200, 16 | 249, 17 | 400, 18 | 499, 19 | 800, 20 | 998, 21 | 1113, 22 | 1209 23 | ], 24 | "corePower": [ 25 | 48, 26 | 54, 27 | 80, 28 | 96, 29 | 144, 30 | 176, 31 | 200, 32 | 224 33 | ], 34 | "clusterPower": [ 35 | 12, 36 | 14, 37 | 20, 38 | 24, 39 | 36, 40 | 44, 41 | 50, 42 | 56 43 | ], 44 | "author": "梦鲲@酷安", 45 | "comment": "使用峰值功耗估计" 46 | }, 47 | { 48 | "coreNum": 4, 49 | "efficiency": 1024, 50 | "minFreq": 200, 51 | "maxFreq": 1497, 52 | "opp": [ 53 | 200, 54 | 345, 55 | 400, 56 | 533, 57 | 800, 58 | 960, 59 | 1113, 60 | 1344, 61 | 1459, 62 | 1497 63 | ], 64 | "corePower": [ 65 | 48, 66 | 68, 67 | 80, 68 | 104, 69 | 144, 70 | 172, 71 | 200, 72 | 288, 73 | 360, 74 | 400 75 | ], 76 | "clusterPower": [ 77 | 12, 78 | 17, 79 | 20, 80 | 26, 81 | 36, 82 | 43, 83 | 50, 84 | 72, 85 | 90, 86 | 100 87 | ], 88 | "author": "梦鲲@酷安", 89 | "comment": "使用峰值功耗估计" 90 | } 91 | ] 92 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm625.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm625", 3 | "device": "模拟", 4 | "enoughCapacityPct": 89, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": false, 8 | "cluster": [ 9 | { 10 | "coreNum": 4, 11 | "efficiency": 1024, 12 | "minFreq": 652, 13 | "maxFreq": 2016, 14 | "opp": [ 15 | 652, 16 | 1036, 17 | 1401, 18 | 1689, 19 | 1804, 20 | 1958, 21 | 2016 22 | ], 23 | "corePower": [ 24 | 44, 25 | 68, 26 | 108, 27 | 176, 28 | 208, 29 | 256, 30 | 280 31 | ], 32 | "clusterPower": [ 33 | 11, 34 | 17, 35 | 27, 36 | 44, 37 | 52, 38 | 64, 39 | 70 40 | ], 41 | "author": "yc9559@酷安", 42 | "comment": "sdm660 线性回归" 43 | } 44 | ] 45 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm626.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm626", 3 | "device": "模拟", 4 | "enoughCapacityPct": 80, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": true, 8 | "cluster": [ 9 | { 10 | "coreNum": 4, 11 | "efficiency": 1024, 12 | "minFreq": 652, 13 | "maxFreq": 2208, 14 | "opp": [ 15 | 652, 16 | 1036, 17 | 1401, 18 | 1689, 19 | 1804, 20 | 1958, 21 | 2016, 22 | 2150, 23 | 2208 24 | ], 25 | "corePower": [ 26 | 44, 27 | 68, 28 | 108, 29 | 176, 30 | 208, 31 | 256, 32 | 280, 33 | 336, 34 | 384 35 | ], 36 | "clusterPower": [ 37 | 11, 38 | 17, 39 | 27, 40 | 44, 41 | 52, 42 | 64, 43 | 70, 44 | 84, 45 | 96 46 | ], 47 | "author": "yc9559@酷安", 48 | "comment": "sdm660 线性回归" 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm636.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm636", 3 | "device": "坚果 Pro 2 模拟", 4 | "enoughCapacityPct": 95, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": true, 8 | "cluster": [ 9 | { 10 | "coreNum": 4, 11 | "efficiency": 1024, 12 | "minFreq": 633, 13 | "maxFreq": 1612, 14 | "opp": [ 15 | 633, 16 | 902, 17 | 1113, 18 | 1401, 19 | 1536, 20 | 1612 21 | ], 22 | "corePower": [ 23 | 44, 24 | 56, 25 | 76, 26 | 108, 27 | 148, 28 | 160 29 | ], 30 | "clusterPower": [ 31 | 11, 32 | 14, 33 | 19, 34 | 27, 35 | 37, 36 | 40 37 | ], 38 | "author": "yc9559@酷安", 39 | "comment": "sdm660 线性回归" 40 | }, 41 | { 42 | "coreNum": 4, 43 | "efficiency": 1638, 44 | "minFreq": 1113, 45 | "maxFreq": 1804, 46 | "opp": [ 47 | 1113, 48 | 1401, 49 | 1747, 50 | 1804 51 | ], 52 | "corePower": [ 53 | 340, 54 | 464, 55 | 688, 56 | 760 57 | ], 58 | "clusterPower": [ 59 | 85, 60 | 116, 61 | 172, 62 | 190 63 | ], 64 | "author": "yc9559@酷安", 65 | "comment": "sdm660 线性回归" 66 | } 67 | ] 68 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm650_652_653.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm650_652_653", 3 | "device": "模拟", 4 | "enoughCapacityPct": 89, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": false, 8 | "cluster": [ 9 | { 10 | "coreNum": 4, 11 | "efficiency": 1024, 12 | "minFreq": 400, 13 | "maxFreq": 1401, 14 | "opp": [ 15 | 400, 16 | 691, 17 | 806, 18 | 1017, 19 | 1190, 20 | 1305, 21 | 1382, 22 | 1401 23 | ], 24 | "corePower": [ 25 | 48, 26 | 64, 27 | 76, 28 | 108, 29 | 148, 30 | 176, 31 | 200, 32 | 208 33 | ], 34 | "clusterPower": [ 35 | 12, 36 | 16, 37 | 19, 38 | 27, 39 | 37, 40 | 44, 41 | 50, 42 | 52 43 | ], 44 | "author": "yc9559@酷安", 45 | "comment": "P = C * freq * volt^2 趋势估计" 46 | }, 47 | { 48 | "coreNum": 4, 49 | "efficiency": 1536, 50 | "minFreq": 400, 51 | "maxFreq": 1804, 52 | "opp": [ 53 | 400, 54 | 883, 55 | 940, 56 | 998, 57 | 1056, 58 | 1113, 59 | 1190, 60 | 1248, 61 | 1305, 62 | 1382, 63 | 1612, 64 | 1747, 65 | 1804 66 | ], 67 | "corePower": [ 68 | 176, 69 | 336, 70 | 360, 71 | 400, 72 | 448, 73 | 480, 74 | 544, 75 | 592, 76 | 640, 77 | 704, 78 | 1000, 79 | 1240, 80 | 1440 81 | ], 82 | "clusterPower": [ 83 | 44, 84 | 84, 85 | 90, 86 | 100, 87 | 112, 88 | 120, 89 | 136, 90 | 148, 91 | 160, 92 | 176, 93 | 250, 94 | 310, 95 | 360 96 | ], 97 | "author": "yc9559@酷安", 98 | "comment": "P = C * freq * volt^2 趋势估计" 99 | } 100 | ] 101 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm660.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm660", 3 | "device": "坚果 Pro 2", 4 | "enoughCapacityPct": 88, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": true, 8 | "cluster": [ 9 | { 10 | "coreNum": 4, 11 | "efficiency": 1024, 12 | "minFreq": 633, 13 | "maxFreq": 1843, 14 | "opp": [ 15 | 633, 16 | 902, 17 | 1113, 18 | 1401, 19 | 1536, 20 | 1747, 21 | 1843 22 | ], 23 | "corePower": [ 24 | 44, 25 | 56, 26 | 76, 27 | 108, 28 | 148, 29 | 188, 30 | 212 31 | ], 32 | "clusterPower": [ 33 | 11, 34 | 14, 35 | 19, 36 | 27, 37 | 37, 38 | 47, 39 | 53 40 | ], 41 | "author": "yc9559@酷安", 42 | "comment": "GPUFLOPS-1.60-MIX2-1T-32KB-2s-cpubind-2min" 43 | }, 44 | { 45 | "coreNum": 4, 46 | "efficiency": 1638, 47 | "minFreq": 1113, 48 | "maxFreq": 2208, 49 | "opp": [ 50 | 1113, 51 | 1401, 52 | 1747, 53 | 1958, 54 | 2150, 55 | 2208 56 | ], 57 | "corePower": [ 58 | 340, 59 | 464, 60 | 688, 61 | 880, 62 | 1072, 63 | 1456 64 | ], 65 | "clusterPower": [ 66 | 85, 67 | 116, 68 | 172, 69 | 220, 70 | 268, 71 | 364 72 | ], 73 | "author": "yc9559@酷安", 74 | "comment": "GPUFLOPS-1.60-MIX2-1T-32KB-2s-cpubind-2min" 75 | } 76 | ] 77 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm820.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm820", 3 | "device": "小米5 模拟", 4 | "enoughCapacityPct": 79, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": true, 8 | "cluster": [ 9 | { 10 | "coreNum": 2, 11 | "efficiency": 1664, 12 | "minFreq": 307, 13 | "maxFreq": 1593, 14 | "opp": [ 15 | 307, 16 | 422, 17 | 480, 18 | 556, 19 | 652, 20 | 729, 21 | 844, 22 | 960, 23 | 1036, 24 | 1113, 25 | 1190, 26 | 1228, 27 | 1324, 28 | 1401, 29 | 1478, 30 | 1593 31 | ], 32 | "corePower": [ 33 | 89, 34 | 118, 35 | 135, 36 | 161, 37 | 194, 38 | 228, 39 | 287, 40 | 359, 41 | 414, 42 | 473, 43 | 536, 44 | 570, 45 | 655, 46 | 735, 47 | 824, 48 | 955 49 | ], 50 | "clusterPower": [ 51 | 22, 52 | 30, 53 | 34, 54 | 40, 55 | 49, 56 | 57, 57 | 72, 58 | 90, 59 | 103, 60 | 118, 61 | 134, 62 | 143, 63 | 164, 64 | 184, 65 | 206, 66 | 239 67 | ], 68 | "author": "yc9559@酷安", 69 | "comment": "使用叶落情殇实测数据线性回归" 70 | }, 71 | { 72 | "coreNum": 2, 73 | "efficiency": 1664, 74 | "minFreq": 307, 75 | "maxFreq": 2150, 76 | "opp": [ 77 | 307, 78 | 403, 79 | 480, 80 | 556, 81 | 652, 82 | 729, 83 | 806, 84 | 883, 85 | 940, 86 | 1036, 87 | 1113, 88 | 1190, 89 | 1248, 90 | 1324, 91 | 1401, 92 | 1478, 93 | 1555, 94 | 1632, 95 | 1708, 96 | 1785, 97 | 1824, 98 | 1920, 99 | 1996, 100 | 2073, 101 | 2150 102 | ], 103 | "corePower": [ 104 | 84, 105 | 106, 106 | 122, 107 | 139, 108 | 182, 109 | 215, 110 | 253, 111 | 296, 112 | 321, 113 | 376, 114 | 422, 115 | 473, 116 | 524, 117 | 587, 118 | 659, 119 | 735, 120 | 828, 121 | 908, 122 | 1014, 123 | 1119, 124 | 1170, 125 | 1352, 126 | 1521, 127 | 1656, 128 | 1913 129 | ], 130 | "clusterPower": [ 131 | 21, 132 | 26, 133 | 31, 134 | 35, 135 | 45, 136 | 54, 137 | 63, 138 | 74, 139 | 80, 140 | 94, 141 | 106, 142 | 118, 143 | 131, 144 | 147, 145 | 165, 146 | 184, 147 | 207, 148 | 227, 149 | 253, 150 | 280, 151 | 293, 152 | 338, 153 | 380, 154 | 414, 155 | 478 156 | ], 157 | "author": "yc9559@酷安", 158 | "comment": "使用叶落情殇实测数据线性回归" 159 | } 160 | ] 161 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm821_v1.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm821_v1", 3 | "device": "小米5p 模拟 1.6G 2.0G", 4 | "enoughCapacityPct": 85, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": true, 8 | "cluster": [ 9 | { 10 | "coreNum": 2, 11 | "efficiency": 1664, 12 | "minFreq": 307, 13 | "maxFreq": 1593, 14 | "opp": [ 15 | 307, 16 | 403, 17 | 480, 18 | 556, 19 | 652, 20 | 729, 21 | 806, 22 | 844, 23 | 883, 24 | 960, 25 | 1036, 26 | 1113, 27 | 1228, 28 | 1248, 29 | 1324, 30 | 1401, 31 | 1555, 32 | 1593 33 | ], 34 | "corePower": [ 35 | 89, 36 | 118, 37 | 135, 38 | 161, 39 | 194, 40 | 228, 41 | 287, 42 | 312, 43 | 328, 44 | 384, 45 | 432, 46 | 473, 47 | 570, 48 | 584, 49 | 655, 50 | 735, 51 | 880, 52 | 955 53 | ], 54 | "clusterPower": [ 55 | 22, 56 | 30, 57 | 34, 58 | 40, 59 | 49, 60 | 57, 61 | 72, 62 | 78, 63 | 82, 64 | 96, 65 | 108, 66 | 118, 67 | 143, 68 | 146, 69 | 164, 70 | 184, 71 | 220, 72 | 239 73 | ], 74 | "author": "yc9559@酷安", 75 | "comment": "使用叶落情殇实测数据线性回归" 76 | }, 77 | { 78 | "coreNum": 2, 79 | "efficiency": 1664, 80 | "minFreq": 307, 81 | "maxFreq": 1996, 82 | "opp": [ 83 | 307, 84 | 403, 85 | 480, 86 | 556, 87 | 652, 88 | 729, 89 | 806, 90 | 844, 91 | 883, 92 | 960, 93 | 1036, 94 | 1113, 95 | 1228, 96 | 1248, 97 | 1324, 98 | 1401, 99 | 1555, 100 | 1593, 101 | 1632, 102 | 1708, 103 | 1824, 104 | 1920, 105 | 1996 106 | ], 107 | "corePower": [ 108 | 84, 109 | 106, 110 | 122, 111 | 139, 112 | 182, 113 | 215, 114 | 253, 115 | 268, 116 | 296, 117 | 321, 118 | 376, 119 | 422, 120 | 488, 121 | 512, 122 | 587, 123 | 659, 124 | 828, 125 | 864, 126 | 908, 127 | 1014, 128 | 1170, 129 | 1352, 130 | 1521 131 | ], 132 | "clusterPower": [ 133 | 21, 134 | 26, 135 | 31, 136 | 35, 137 | 45, 138 | 54, 139 | 63, 140 | 67, 141 | 74, 142 | 80, 143 | 94, 144 | 106, 145 | 122, 146 | 128, 147 | 147, 148 | 165, 149 | 207, 150 | 216, 151 | 227, 152 | 253, 153 | 293, 154 | 338, 155 | 380 156 | ], 157 | "author": "yc9559@酷安", 158 | "comment": "使用叶落情殇实测数据线性回归" 159 | } 160 | ] 161 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm821_v2.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm821_v2", 3 | "device": "小米5p 模拟 2.0G 2.1G", 4 | "enoughCapacityPct": 81, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": true, 8 | "cluster": [ 9 | { 10 | "coreNum": 2, 11 | "efficiency": 1664, 12 | "minFreq": 307, 13 | "maxFreq": 1593, 14 | "opp": [ 15 | 307, 16 | 384, 17 | 460, 18 | 537, 19 | 614, 20 | 691, 21 | 768, 22 | 844, 23 | 902, 24 | 979, 25 | 1056, 26 | 1132, 27 | 1209, 28 | 1286, 29 | 1363, 30 | 1440, 31 | 1516, 32 | 1593, 33 | 1996 34 | ], 35 | "corePower": [ 36 | 74, 37 | 92, 38 | 113, 39 | 130, 40 | 148, 41 | 176, 42 | 204, 43 | 239, 44 | 271, 45 | 313, 46 | 348, 47 | 401, 48 | 454, 49 | 517, 50 | 563, 51 | 644, 52 | 715, 53 | 796, 54 | 1440 55 | ], 56 | "clusterPower": [ 57 | 18, 58 | 23, 59 | 28, 60 | 33, 61 | 37, 62 | 44, 63 | 51, 64 | 60, 65 | 68, 66 | 78, 67 | 87, 68 | 100, 69 | 114, 70 | 129, 71 | 141, 72 | 161, 73 | 179, 74 | 199, 75 | 360 76 | ], 77 | "author": "yc9559@酷安", 78 | "comment": "使用叶落情殇实测数据线性回归" 79 | }, 80 | { 81 | "coreNum": 2, 82 | "efficiency": 1664, 83 | "minFreq": 307, 84 | "maxFreq": 2150, 85 | "opp": [ 86 | 307, 87 | 384, 88 | 460, 89 | 537, 90 | 614, 91 | 691, 92 | 748, 93 | 825, 94 | 902, 95 | 979, 96 | 1056, 97 | 1132, 98 | 1209, 99 | 1286, 100 | 1363, 101 | 1440, 102 | 1516, 103 | 1593, 104 | 1670, 105 | 1747, 106 | 1824, 107 | 1900, 108 | 1977, 109 | 2054, 110 | 2150 111 | ], 112 | "corePower": [ 113 | 70, 114 | 84, 115 | 99, 116 | 113, 117 | 127, 118 | 141, 119 | 155, 120 | 197, 121 | 225, 122 | 271, 123 | 317, 124 | 356, 125 | 412, 126 | 458, 127 | 524, 128 | 577, 129 | 648, 130 | 739, 131 | 803, 132 | 876, 133 | 975, 134 | 1091, 135 | 1186, 136 | 1345, 137 | 1595 138 | ], 139 | "clusterPower": [ 140 | 18, 141 | 21, 142 | 25, 143 | 28, 144 | 32, 145 | 35, 146 | 39, 147 | 49, 148 | 56, 149 | 68, 150 | 79, 151 | 89, 152 | 103, 153 | 114, 154 | 131, 155 | 144, 156 | 162, 157 | 185, 158 | 201, 159 | 219, 160 | 244, 161 | 273, 162 | 297, 163 | 336, 164 | 399 165 | ], 166 | "author": "yc9559@酷安", 167 | "comment": "使用叶落情殇实测数据线性回归" 168 | } 169 | ] 170 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm821_v3.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm821_v3", 3 | "device": "ZUK Edge 2.1G 2.3G", 4 | "enoughCapacityPct": 74, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": true, 8 | "cluster": [ 9 | { 10 | "coreNum": 2, 11 | "efficiency": 1664, 12 | "minFreq": 307, 13 | "maxFreq": 1593, 14 | "opp": [ 15 | 307, 16 | 384, 17 | 460, 18 | 537, 19 | 614, 20 | 691, 21 | 768, 22 | 844, 23 | 902, 24 | 979, 25 | 1056, 26 | 1132, 27 | 1209, 28 | 1286, 29 | 1363, 30 | 1440, 31 | 1516, 32 | 1593, 33 | 2188 34 | ], 35 | "corePower": [ 36 | 74, 37 | 92, 38 | 113, 39 | 130, 40 | 148, 41 | 176, 42 | 204, 43 | 239, 44 | 271, 45 | 313, 46 | 348, 47 | 401, 48 | 454, 49 | 517, 50 | 563, 51 | 644, 52 | 715, 53 | 796, 54 | 1820 55 | ], 56 | "clusterPower": [ 57 | 18, 58 | 23, 59 | 28, 60 | 33, 61 | 37, 62 | 44, 63 | 51, 64 | 60, 65 | 68, 66 | 78, 67 | 87, 68 | 100, 69 | 114, 70 | 129, 71 | 141, 72 | 161, 73 | 179, 74 | 199, 75 | 455 76 | ], 77 | "author": "yc9559@酷安", 78 | "comment": "使用叶落情殇实测数据" 79 | }, 80 | { 81 | "coreNum": 2, 82 | "efficiency": 1664, 83 | "minFreq": 307, 84 | "maxFreq": 2342, 85 | "opp": [ 86 | 307, 87 | 384, 88 | 460, 89 | 537, 90 | 614, 91 | 691, 92 | 748, 93 | 825, 94 | 902, 95 | 979, 96 | 1056, 97 | 1132, 98 | 1209, 99 | 1286, 100 | 1363, 101 | 1440, 102 | 1516, 103 | 1593, 104 | 1670, 105 | 1747, 106 | 1824, 107 | 1900, 108 | 1977, 109 | 2054, 110 | 2150, 111 | 2246, 112 | 2342 113 | ], 114 | "corePower": [ 115 | 70, 116 | 84, 117 | 99, 118 | 113, 119 | 127, 120 | 141, 121 | 155, 122 | 197, 123 | 225, 124 | 271, 125 | 317, 126 | 356, 127 | 412, 128 | 458, 129 | 524, 130 | 577, 131 | 648, 132 | 739, 133 | 803, 134 | 876, 135 | 975, 136 | 1091, 137 | 1186, 138 | 1345, 139 | 1595, 140 | 1820, 141 | 2010 142 | ], 143 | "clusterPower": [ 144 | 18, 145 | 21, 146 | 25, 147 | 28, 148 | 32, 149 | 35, 150 | 39, 151 | 49, 152 | 56, 153 | 68, 154 | 79, 155 | 89, 156 | 103, 157 | 114, 158 | 131, 159 | 144, 160 | 162, 161 | 185, 162 | 201, 163 | 219, 164 | 244, 165 | 273, 166 | 297, 167 | 336, 168 | 399, 169 | 455, 170 | 502 171 | ], 172 | "author": "yc9559@酷安", 173 | "comment": "使用叶落情殇实测数据" 174 | } 175 | ] 176 | } -------------------------------------------------------------------------------- /dataset/soc_model/model_sdm835.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdm835", 3 | "device": "小米6 模拟", 4 | "enoughCapacityPct": 83, 5 | "sched": "walt", 6 | "intra": "smp", 7 | "inputBoost": true, 8 | "cluster": [ 9 | { 10 | "coreNum": 4, 11 | "efficiency": 1024, 12 | "minFreq": 300, 13 | "maxFreq": 1900, 14 | "opp": [ 15 | 300, 16 | 364, 17 | 441, 18 | 518, 19 | 595, 20 | 672, 21 | 748, 22 | 825, 23 | 883, 24 | 960, 25 | 1036, 26 | 1094, 27 | 1171, 28 | 1248, 29 | 1324, 30 | 1401, 31 | 1478, 32 | 1555, 33 | 1670, 34 | 1747, 35 | 1824, 36 | 1900 37 | ], 38 | "corePower": [ 39 | 67, 40 | 70, 41 | 77, 42 | 84, 43 | 92, 44 | 99, 45 | 106, 46 | 113, 47 | 120, 48 | 127, 49 | 134, 50 | 141, 51 | 151, 52 | 158, 53 | 165, 54 | 172, 55 | 183, 56 | 194, 57 | 208, 58 | 218, 59 | 229, 60 | 257 61 | ], 62 | "clusterPower": [ 63 | 17, 64 | 18, 65 | 19, 66 | 21, 67 | 23, 68 | 25, 69 | 26, 70 | 28, 71 | 30, 72 | 32, 73 | 33, 74 | 35, 75 | 38, 76 | 40, 77 | 41, 78 | 43, 79 | 46, 80 | 48, 81 | 52, 82 | 55, 83 | 57, 84 | 64 85 | ], 86 | "author": "yc9559@酷安", 87 | "comment": "使用叶落情殇实测数据线性回归" 88 | }, 89 | { 90 | "coreNum": 4, 91 | "efficiency": 1638, 92 | "minFreq": 300, 93 | "maxFreq": 2361, 94 | "opp": [ 95 | 300, 96 | 345, 97 | 422, 98 | 499, 99 | 576, 100 | 652, 101 | 729, 102 | 806, 103 | 902, 104 | 979, 105 | 1056, 106 | 1132, 107 | 1190, 108 | 1267, 109 | 1344, 110 | 1420, 111 | 1497, 112 | 1574, 113 | 1651, 114 | 1728, 115 | 1804, 116 | 1881, 117 | 1958, 118 | 2035, 119 | 2112, 120 | 2265, 121 | 2342, 122 | 2361, 123 | 2457 124 | ], 125 | "corePower": [ 126 | 137, 127 | 141, 128 | 155, 129 | 169, 130 | 176, 131 | 190, 132 | 204, 133 | 215, 134 | 232, 135 | 243, 136 | 253, 137 | 264, 138 | 285, 139 | 306, 140 | 334, 141 | 359, 142 | 394, 143 | 433, 144 | 468, 145 | 496, 146 | 549, 147 | 605, 148 | 655, 149 | 722, 150 | 792, 151 | 1021, 152 | 1126, 153 | 1144, 154 | 1338 155 | ], 156 | "clusterPower": [ 157 | 34, 158 | 35, 159 | 39, 160 | 42, 161 | 44, 162 | 48, 163 | 51, 164 | 54, 165 | 58, 166 | 61, 167 | 63, 168 | 66, 169 | 71, 170 | 77, 171 | 84, 172 | 90, 173 | 99, 174 | 108, 175 | 117, 176 | 124, 177 | 137, 178 | 151, 179 | 164, 180 | 180, 181 | 198, 182 | 255, 183 | 282, 184 | 286, 185 | 334 186 | ], 187 | "author": "yc9559@酷安", 188 | "comment": "使用叶落情殇实测数据线性回归" 189 | } 190 | ] 191 | } -------------------------------------------------------------------------------- /dataset/soc_model/raw/e7420.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/dataset/soc_model/raw/e7420.xlsx -------------------------------------------------------------------------------- /dataset/soc_model/raw/e8890.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/dataset/soc_model/raw/e8890.xlsx -------------------------------------------------------------------------------- /dataset/soc_model/raw/e8895.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/dataset/soc_model/raw/e8895.xlsx -------------------------------------------------------------------------------- /dataset/soc_model/raw/sd626.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/dataset/soc_model/raw/sd626.xlsx -------------------------------------------------------------------------------- /dataset/soc_model/raw/sd820.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/dataset/soc_model/raw/sd820.xlsx -------------------------------------------------------------------------------- /dataset/soc_model/raw/sd821.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/dataset/soc_model/raw/sd821.xlsx -------------------------------------------------------------------------------- /dataset/soc_model/raw/sd835.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/dataset/soc_model/raw/sd835.xlsx -------------------------------------------------------------------------------- /dataset/soc_model/raw/sdm616.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/dataset/soc_model/raw/sdm616.xlsx -------------------------------------------------------------------------------- /dataset/soc_model/raw/sdm636.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/dataset/soc_model/raw/sdm636.xlsx -------------------------------------------------------------------------------- /dataset/soc_model/raw/sdm650.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/dataset/soc_model/raw/sdm650.xlsx -------------------------------------------------------------------------------- /dataset/soc_model/raw/sdm660.csv: -------------------------------------------------------------------------------- 1 | item,GPUFLOPS-1.60-MIX2-1T-32KB-2s-cpubind-2min,,,,, 2 | cluster,freq,totalpwr,pwr,perf/pwr,corepwr(0.8 * pwr),clusterpwr(0.2 * pwr) 3 | idle,,,795,,, 4 | little,633,850,55,11785.30909,44,11 5 | little,902,865,70,13194.97143,56,14 6 | little,1113,890,95,11996.96842,76,19 7 | little,1401,930,135,10626.84444,108,27 8 | little,1536,980,185,8501.967568,148,37 9 | little,1747,1030,235,7612.459574,188,47 10 | little,1843,1060,265,7121.630189,212,53 11 | big,1113,1220,425,4289.632941,340,85 12 | big,1401,1375,580,3956.617241,464,116 13 | big,1747,1675,860,3327.425581,688,172 14 | big,1958,1900,1100,2915.64,880,220 15 | big,2150,2130,1340,2628.134328,1072,268 16 | big,2208,2630,1820,1987.2,1456,364 17 | -------------------------------------------------------------------------------- /dataset/workload/osborn/bili-download.json: -------------------------------------------------------------------------------- 1 | {"src":["bili-download.html"],"ver":1,"quantumSec":0.001,"windowQuantum":10,"frameQuantum":16,"efficiencyA53":1024,"efficiency":1638,"freq":2208,"loadScale":100,"coreNum":4,"windowedLoadLen":1332,"windowedLoad":[[25,13,25,1,0,0],[16,16,16,11,3,0],[23,15,23,3,2,0],[16,16,10,5,2,0],[13,12,13,9,3,0],[29,14,29,4,4,0],[26,22,26,7,2,0],[32,29,32,12,0,0],[17,9,17,0,0,0],[16,12,16,2,4,0],[23,23,16,6,1,0],[23,21,23,21,0,0],[29,13,29,2,0,0],[23,23,20,8,4,0],[13,9,13,1,1,0],[16,16,10,16,1,0],[21,21,15,6,0,0],[23,23,14,11,12,0],[25,25,21,10,4,0],[26,26,23,7,0,0],[2,2,1,0,0,0],[17,16,17,10,2,0],[28,28,19,16,5,0],[20,20,20,13,13,0],[51,51,26,16,12,0],[88,15,88,12,6,0],[70,37,70,17,10,0],[55,55,46,47,46,0],[43,21,43,9,18,0],[100,47,59,36,100,0],[20,20,13,3,15,0],[17,17,14,9,2,0],[25,14,25,5,0,0],[33,26,33,9,2,0],[26,21,26,16,2,0],[30,26,30,19,12,0],[17,17,13,10,6,0],[36,36,30,21,0,0],[47,47,31,39,17,0],[51,32,41,51,18,0],[36,36,28,29,7,0],[23,16,23,7,1,0],[23,23,14,6,7,0],[23,12,23,6,1,0],[25,18,25,11,3,0],[27,17,27,0,3,0],[26,21,26,8,1,0],[19,19,13,0,0,0],[21,19,21,8,0,0],[16,16,14,5,1,0],[34,21,34,6,9,0],[32,26,32,12,5,0],[33,15,33,6,2,0],[11,9,11,0,4,0],[21,21,19,6,7,0],[21,11,21,4,0,0],[27,13,27,0,0,0],[22,19,22,12,2,0],[26,20,26,9,9,0],[9,9,3,0,0,0],[24,22,24,10,0,0],[25,15,25,8,0,0],[22,14,22,7,4,0],[29,29,19,8,6,0],[20,12,20,1,4,0],[13,11,13,2,5,0],[21,21,8,4,8,0],[25,12,25,8,4,0],[24,14,24,9,6,0],[19,19,19,14,3,0],[7,7,6,0,0,0],[21,21,13,5,15,0],[22,19,22,6,3,0],[27,21,27,10,2,0],[26,26,15,7,17,0],[19,19,17,1,14,0],[9,9,9,0,0,0],[19,6,19,2,3,0],[25,24,25,4,4,0],[24,24,12,16,0,0],[22,17,22,10,10,0],[19,8,19,1,0,0],[24,24,11,6,10,0],[22,22,21,5,3,0],[25,19,25,4,3,0],[26,18,26,0,3,0],[24,24,20,6,3,0],[27,20,27,11,0,0],[15,15,8,4,7,0],[13,7,13,0,0,0],[26,15,26,1,1,0],[27,22,27,6,3,0],[56,56,27,33,13,0],[68,68,14,2,0,0],[71,71,22,20,4,0],[59,59,41,36,22,0],[27,14,27,5,0,0],[27,19,27,9,3,0],[27,24,27,4,2,0],[13,10,13,2,5,0],[15,15,6,6,8,0],[28,14,28,0,0,0],[29,15,29,5,5,0],[28,19,28,5,4,0],[24,24,14,12,17,0],[11,11,9,7,5,0],[16,16,13,7,9,0],[39,39,23,19,1,0],[26,22,26,7,4,0],[32,19,32,10,0,0],[20,14,20,10,5,0],[8,5,8,3,4,0],[23,18,23,12,1,0],[22,22,19,11,1,0],[29,19,29,9,7,0],[26,26,20,5,0,0],[12,10,12,1,0,0],[13,10,13,6,0,0],[29,29,26,8,3,0],[27,24,27,16,7,0],[19,15,19,0,0,0],[14,9,14,8,0,0],[20,20,18,8,3,0],[16,16,6,12,5,0],[74,74,38,23,27,0],[85,58,21,85,29,0],[74,38,34,74,6,0],[43,43,33,33,17,0],[23,23,13,10,16,0],[38,38,33,22,27,0],[50,50,30,11,1,0],[26,26,22,7,7,0],[24,24,19,8,2,0],[11,7,11,2,2,0],[17,17,17,2,4,0],[21,20,21,5,2,0],[31,27,31,14,18,0],[25,25,14,13,3,0],[68,51,68,20,9,0],[47,33,27,20,47,0],[30,30,30,22,1,0],[26,26,26,24,7,0],[31,25,31,15,4,0],[34,34,21,8,4,0],[14,14,10,3,0,0],[20,20,11,0,12,0],[30,21,30,8,6,0],[27,16,27,15,19,0],[25,24,25,4,3,0],[28,28,18,10,17,0],[9,9,6,3,1,0],[46,46,43,8,6,0],[24,22,24,11,1,0],[29,16,29,8,20,0],[24,24,24,14,11,0],[17,17,14,1,0,0],[14,14,12,8,3,0],[17,13,17,11,1,0],[24,20,24,2,1,0],[23,11,13,9,23,0],[12,9,12,2,4,0],[20,13,20,1,0,0],[22,22,18,5,4,0],[25,25,18,17,3,0],[27,19,27,14,1,0],[22,22,21,8,3,0],[12,12,12,3,0,0],[24,24,9,6,3,0],[26,19,26,1,0,0],[28,22,28,7,2,0],[30,17,30,8,0,0],[28,28,19,13,7,0],[8,7,8,2,0,0],[18,10,18,0,0,0],[24,16,24,10,0,0],[30,30,22,13,4,0],[27,18,27,4,1,0],[19,11,19,5,1,0],[24,24,17,8,8,0],[28,28,23,8,0,0],[25,20,25,7,2,0],[21,21,20,8,1,0],[30,12,30,2,1,0],[11,10,11,0,1,0],[23,17,23,7,3,0],[16,16,11,13,2,0],[25,25,15,6,8,0],[24,24,19,14,5,0],[24,20,24,8,4,0],[10,5,10,1,2,0],[14,14,13,7,2,0],[23,23,19,15,7,0],[23,23,22,6,6,0],[27,11,27,6,0,0],[21,10,21,0,0,0],[59,59,9,6,11,0],[27,15,27,4,1,0],[28,14,28,6,3,0],[29,14,29,0,0,0],[31,31,17,17,7,0],[0,0,0,0,0,0],[21,21,14,11,20,0],[24,15,24,6,1,0],[20,15,20,1,1,0],[28,26,28,6,2,0],[76,76,28,12,6,0],[46,46,22,17,11,0],[86,86,17,21,6,0],[52,49,52,22,6,0],[16,9,16,0,0,0],[15,7,15,3,2,0],[26,19,26,21,1,0],[25,20,25,8,0,0],[25,20,25,3,3,0],[15,12,15,8,2,0],[21,21,13,8,0,0],[20,9,20,0,0,0],[30,18,30,8,7,0],[23,18,23,15,0,0],[32,32,24,13,4,0],[14,10,14,0,0,0],[21,14,21,5,0,0],[21,7,21,1,4,0],[30,21,30,16,5,0],[42,42,18,29,10,0],[87,87,19,25,10,0],[75,75,19,2,1,0],[40,40,22,13,5,0],[50,50,36,30,32,0],[45,45,23,39,11,0],[29,17,29,5,2,0],[18,12,18,6,1,0],[17,14,17,12,0,0],[18,18,10,15,1,0],[41,22,41,9,0,0],[43,19,43,9,6,0],[18,14,18,3,0,0],[20,20,4,13,1,0],[59,59,42,30,9,0],[73,73,52,31,28,0],[29,16,29,3,9,0],[41,39,41,7,7,0],[26,26,16,15,0,0],[16,12,16,12,14,0],[31,12,31,2,2,0],[25,13,25,0,0,0],[25,18,25,11,0,0],[24,24,21,14,0,0],[14,8,14,3,0,0],[15,15,13,5,0,0],[26,12,26,2,1,0],[64,31,64,24,28,0],[100,29,100,24,14,0],[31,12,31,0,0,0],[14,13,14,5,1,0],[19,19,12,6,4,0],[23,23,22,6,16,0],[20,17,20,14,3,0],[28,20,28,10,2,0],[15,14,15,5,1,0],[13,13,9,2,7,0],[23,16,23,9,0,0],[27,20,27,4,2,0],[33,26,33,13,3,0],[15,12,15,4,3,0],[9,9,2,4,2,0],[30,15,30,7,0,0],[25,18,25,8,7,0],[29,21,29,11,0,0],[27,13,27,1,0,0],[15,15,14,4,1,0],[9,8,9,9,1,0],[25,14,25,0,0,0],[30,13,30,5,0,0],[26,26,24,3,3,0],[31,31,22,8,9,0],[16,11,16,4,0,0],[13,11,13,3,0,0],[16,14,16,10,0,0],[34,18,34,7,5,0],[22,14,22,15,3,0],[20,14,20,3,1,0],[18,11,18,4,0,0],[24,11,24,3,1,0],[21,21,17,4,5,0],[26,26,15,4,0,0],[28,15,28,2,2,0],[30,30,13,2,1,0],[15,15,9,4,4,0],[22,22,16,10,3,0],[27,15,27,5,3,0],[22,22,20,17,3,0],[13,7,13,1,0,0],[23,22,23,9,2,0],[16,10,16,11,2,0],[35,28,28,35,5,0],[25,14,25,2,5,0],[19,14,19,5,0,0],[16,16,13,12,1,0],[20,20,16,8,0,0],[24,22,24,9,9,0],[26,13,26,11,4,0],[24,15,24,11,1,0],[27,27,23,0,0,0],[44,44,30,7,0,0],[16,15,16,6,3,0],[24,16,24,8,2,0],[33,33,21,13,8,0],[31,31,16,2,7,0],[22,22,14,6,0,0],[9,9,5,2,0,0],[31,31,10,20,4,0],[25,16,25,7,0,0],[22,17,22,11,3,0],[27,26,27,7,3,0],[23,17,23,10,1,0],[11,5,11,3,0,0],[25,25,20,1,0,0],[93,93,34,31,15,0],[57,57,21,21,16,0],[84,84,40,28,6,0],[1,1,0,0,0,0],[21,16,21,2,4,0],[24,20,24,15,5,0],[57,57,55,25,27,0],[83,83,55,32,12,0],[83,83,10,18,12,0],[31,31,13,13,5,0],[55,55,41,36,21,0],[41,37,41,26,23,0],[29,19,29,9,2,0],[30,30,25,25,16,0],[10,10,8,4,0,0],[21,8,21,1,2,0],[22,18,22,8,2,0],[22,22,22,10,0,0],[1,1,0,0,0,0],[0,0,0,0,0,0],[59,47,59,13,21,0],[88,88,50,45,41,0],[38,38,29,24,21,0],[57,57,30,24,16,0],[27,16,27,4,0,0],[14,10,14,0,1,0],[20,16,20,6,1,0],[26,16,26,2,0,0],[23,23,21,5,0,0],[50,50,33,8,7,0],[17,17,12,3,1,0],[15,8,15,5,3,0],[23,22,23,9,22,0],[28,28,20,7,12,0],[25,21,25,15,1,0],[24,24,21,6,6,0],[13,7,13,1,0,0],[37,17,37,9,7,0],[26,18,26,7,5,0],[27,16,27,4,3,0],[28,13,28,9,9,0],[24,24,19,1,7,0],[11,9,11,4,2,0],[23,15,23,11,3,0],[25,20,25,6,3,0],[20,20,19,18,0,0],[26,25,26,8,3,0],[14,10,14,0,0,0],[24,16,24,3,0,0],[22,22,15,4,6,0],[24,17,24,16,5,0],[18,17,18,8,11,0],[22,22,18,12,1,0],[10,10,4,0,0,0],[17,17,16,11,2,0],[27,27,21,11,7,0],[24,12,24,5,4,0],[26,26,24,13,1,0],[20,20,15,11,2,0],[18,15,18,8,0,0],[17,14,17,3,2,0],[26,26,15,11,6,0],[24,24,18,14,3,0],[25,21,25,13,5,0],[11,11,5,6,1,0],[25,25,17,12,3,0],[32,32,19,10,3,0],[23,23,18,6,11,0],[34,18,34,0,0,0],[25,23,25,11,2,0],[12,8,12,3,1,0],[19,19,9,4,0,0],[29,14,29,0,0,0],[24,20,24,1,8,0],[29,29,23,10,2,0],[15,15,13,9,3,0],[24,10,24,1,4,0],[43,43,28,12,3,0],[23,22,23,16,7,0],[24,17,24,14,3,0],[24,24,23,7,0,0],[13,11,13,4,0,0],[29,29,15,5,4,0],[20,20,11,12,6,0],[21,18,21,17,0,0],[22,22,19,4,0,0],[21,17,21,15,13,0],[17,10,17,0,0,0],[16,4,16,2,0,0],[29,23,29,11,12,0],[25,25,22,16,5,0],[24,19,24,0,0,0],[24,16,24,8,0,0],[14,14,13,4,0,0],[20,20,11,3,11,0],[23,23,15,15,1,0],[26,18,26,6,2,0],[30,30,12,18,4,0],[23,17,23,2,4,0],[15,15,10,0,0,0],[17,3,17,1,0,0],[29,23,29,4,8,0],[22,16,22,10,4,0],[26,26,20,7,0,0],[25,19,25,5,2,0],[16,10,16,0,0,0],[31,31,23,3,1,0],[88,20,23,18,88,0],[64,54,40,13,64,0],[29,29,19,10,12,0],[53,53,30,25,35,0],[28,27,28,20,14,0],[97,97,31,23,28,0],[54,54,19,14,15,0],[61,61,25,18,4,0],[48,45,48,15,6,0],[25,25,25,8,2,0],[16,11,16,2,5,0],[24,21,24,10,8,0],[26,26,13,3,12,0],[24,24,24,7,3,0],[77,77,71,31,27,0],[45,45,42,18,22,0],[45,45,24,9,7,0],[29,29,29,11,3,0],[40,40,18,27,24,0],[24,23,24,17,3,0],[27,27,19,20,9,0],[27,20,27,12,4,0],[15,13,15,3,0,0],[15,15,14,9,1,0],[21,21,16,15,6,0],[24,17,24,8,0,0],[24,21,19,23,24,0],[40,40,29,18,13,0],[19,19,17,5,1,0],[10,10,4,8,4,0],[22,22,18,16,6,0],[25,14,25,9,2,0],[19,18,19,16,0,0],[28,16,28,6,0,0],[21,12,21,3,0,0],[14,14,9,5,3,0],[21,18,21,19,1,0],[20,14,20,3,0,0],[26,26,18,20,3,0],[28,19,28,7,3,0],[11,11,9,8,1,0],[19,19,9,3,3,0],[38,19,38,9,1,0],[28,17,28,2,1,0],[21,21,18,11,1,0],[28,20,28,7,0,0],[15,10,15,5,0,0],[14,14,14,9,1,0],[24,24,19,2,7,0],[28,28,15,7,4,0],[22,22,19,17,4,0],[18,17,18,4,2,0],[20,20,13,3,4,0],[15,12,15,2,0,0],[26,20,26,10,15,0],[30,30,20,4,0,0],[27,15,27,1,0,0],[14,13,14,10,0,0],[20,7,20,7,0,0],[15,12,15,10,0,0],[25,16,25,10,4,0],[63,63,14,15,1,0],[84,84,1,3,0,0],[5,4,5,1,0,0],[1,0,1,1,0,0],[2,2,0,0,0,0],[9,9,3,0,0,0],[6,6,1,1,1,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[4,4,1,0,0,0],[28,28,0,1,1,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[3,3,2,0,0,0],[2,2,0,1,0,0],[3,3,0,0,0,0],[7,4,7,0,0,0],[26,26,10,0,0,0],[2,2,0,1,0,0],[3,0,3,0,0,0],[0,0,0,0,0,0],[3,0,3,0,0,0],[17,3,17,0,0,0],[0,0,0,0,0,0],[0,0,0,0,0,0],[2,0,2,0,0,0],[1,1,1,0,0,0],[47,47,43,15,6,0],[83,83,18,13,6,0],[6,6,3,0,0,0],[2,1,2,1,1,0],[1,1,0,0,0,0],[0,0,0,0,0,0],[7,7,3,2,3,0],[1,1,0,0,0,0],[2,2,0,1,1,0],[96,96,35,9,2,0],[58,43,58,29,24,0],[39,39,34,8,1,0],[100,100,22,50,27,0],[88,88,13,2,0,0],[11,11,11,8,2,0],[7,4,1,6,7,0],[11,11,9,1,1,0],[36,36,18,4,1,0],[15,15,12,2,1,0],[28,28,21,7,2,0],[71,71,57,34,19,0],[30,27,30,5,1,0],[51,51,46,40,30,0],[49,49,21,22,15,0],[45,40,45,19,10,0],[41,41,32,24,27,0],[32,32,32,13,7,0],[53,53,23,29,9,0],[33,30,33,11,0,0],[70,70,29,35,3,0],[81,81,31,27,17,0],[31,20,31,11,3,0],[30,30,27,11,4,0],[37,37,35,15,1,0],[41,41,30,19,10,0],[65,65,41,28,8,0],[55,55,38,23,11,0],[30,25,30,10,1,0],[52,52,47,18,16,0],[42,42,37,15,8,0],[72,72,42,38,19,0],[68,68,32,54,25,0],[36,29,13,36,1,0],[62,62,53,18,11,0],[35,35,19,24,4,0],[18,18,11,3,2,0],[57,53,57,7,10,0],[62,44,62,12,6,0],[52,52,37,22,7,0],[48,43,48,21,0,0],[52,18,19,17,52,0],[100,32,41,22,100,0],[39,39,28,20,21,0],[29,29,19,6,0,0],[49,49,40,20,9,0],[37,27,37,11,0,0],[44,38,44,17,3,0],[47,47,32,25,2,0],[34,34,28,9,0,0],[46,46,29,17,9,0],[49,49,36,19,9,0],[29,24,29,6,8,0],[54,33,54,20,7,0],[32,32,24,17,4,0],[41,41,39,20,6,0],[33,33,29,13,6,0],[20,18,20,14,4,0],[26,21,26,5,7,0],[16,15,16,4,0,0],[15,15,14,5,3,0],[20,20,14,9,0,0],[24,24,15,1,14,0],[24,24,21,15,10,0],[24,18,24,2,3,0],[15,15,12,0,0,0],[18,18,15,7,0,0],[24,24,22,9,4,0],[25,24,25,10,0,0],[21,21,20,15,2,0],[12,6,12,5,0,0],[17,17,15,12,1,0],[18,16,18,13,1,0],[20,18,20,13,3,0],[41,41,27,7,28,0],[23,23,22,11,4,0],[12,12,8,8,0,0],[17,17,5,5,5,0],[21,10,21,16,1,0],[22,21,22,17,8,0],[29,13,29,0,0,0],[17,15,17,4,2,0],[17,17,17,6,0,0],[16,7,16,10,2,0],[16,15,16,14,3,0],[24,21,24,10,7,0],[24,24,19,8,1,0],[11,11,3,3,3,0],[0,0,0,0,0,0],[10,10,3,0,0,0],[1,1,0,0,0,0],[5,5,0,0,1,0],[0,0,0,0,0,0],[3,1,3,0,0,0],[1,1,1,0,0,0],[3,3,0,2,1,0],[1,0,1,0,0,0],[7,2,7,0,1,0],[6,2,6,0,0,0],[32,32,30,22,2,0],[42,42,18,13,2,0],[35,18,35,2,1,0],[47,47,15,5,1,0],[87,29,29,87,14,0],[59,25,32,59,19,0],[43,43,26,10,9,0],[15,8,15,7,0,0],[30,28,30,7,8,0],[24,23,24,4,3,0],[57,37,57,29,28,0],[52,40,52,21,11,0],[29,29,17,11,5,0],[17,12,17,3,2,0],[22,22,15,3,1,0],[19,17,19,6,4,0],[26,26,21,11,3,0],[23,23,21,10,3,0],[32,32,17,5,8,0],[27,27,24,7,5,0],[57,57,25,17,14,0],[27,27,26,10,5,0],[68,68,40,26,8,0],[65,65,11,14,6,0],[58,58,28,13,5,0],[17,17,14,8,3,0],[25,25,18,6,6,0],[21,14,21,14,0,0],[24,24,24,18,2,0],[26,25,26,5,1,0],[40,22,40,13,5,0],[12,12,11,6,2,0],[14,14,14,7,2,0],[34,28,34,9,7,0],[27,18,27,13,3,0],[25,25,23,8,8,0],[23,23,22,6,10,0],[16,13,16,7,3,0],[95,95,37,26,9,0],[17,17,17,8,5,0],[28,28,18,11,3,0],[22,21,22,10,3,0],[23,23,21,12,3,0],[14,10,14,4,0,0],[20,20,12,7,3,0],[21,21,19,6,3,0],[28,28,13,10,8,0],[20,20,20,14,2,0],[25,16,25,11,5,0],[14,14,12,6,0,0],[24,24,13,8,3,0],[21,21,18,5,9,0],[29,29,22,9,4,0],[24,24,24,10,5,0],[30,21,30,6,1,0],[13,8,13,3,0,0],[26,26,12,5,3,0],[18,18,12,7,9,0],[23,22,23,9,4,0],[24,20,24,13,1,0],[24,24,19,14,5,0],[14,14,10,7,0,0],[23,23,14,5,2,0],[20,20,19,7,7,0],[24,24,20,11,0,0],[21,21,17,13,6,0],[24,24,24,5,8,0],[9,9,8,4,0,0],[19,19,10,10,0,0],[21,21,18,12,7,0],[29,19,29,5,3,0],[23,23,20,14,1,0],[24,19,24,18,2,0],[13,13,10,2,2,0],[28,28,14,7,3,0],[48,48,35,13,5,0],[79,79,23,21,3,0],[56,56,41,23,6,0],[23,18,23,6,0,0],[13,12,13,3,1,0],[15,15,14,4,0,0],[28,14,28,1,1,0],[24,19,24,5,8,0],[28,15,28,4,0,0],[13,8,13,3,0,0],[10,7,10,8,1,0],[27,26,27,8,8,0],[28,28,27,4,0,0],[24,21,24,15,0,0],[37,14,37,5,4,0],[16,8,16,1,0,0],[16,16,16,6,5,0],[17,12,17,9,0,0],[23,14,23,8,6,0],[23,23,20,15,7,0],[25,22,25,3,0,0],[13,4,13,0,0,0],[10,9,8,6,10,0],[23,14,23,9,11,0],[24,16,24,6,4,0],[20,20,15,15,1,0],[24,24,22,9,4,0],[12,11,12,7,4,0],[59,59,39,4,7,0],[73,73,57,40,32,0],[84,84,40,26,22,0],[42,42,26,34,15,0],[21,21,19,3,0,0],[20,20,13,5,5,0],[27,16,27,2,1,0],[41,41,26,41,21,0],[39,39,22,17,37,0],[22,22,22,7,1,0],[27,20,27,10,2,0],[16,16,16,1,0,0],[20,20,13,6,0,0],[23,10,23,3,0,0],[31,31,20,6,3,0],[27,27,19,3,7,0],[19,17,19,6,4,0],[54,54,40,32,26,0],[100,88,46,100,62,0],[100,24,38,100,5,0],[82,82,50,52,43,0],[99,99,55,34,29,0],[72,39,72,23,11,0],[32,32,11,17,8,0],[45,13,45,4,4,0],[23,21,23,7,5,0],[27,27,15,12,5,0],[31,12,31,9,9,0],[46,46,31,38,22,0],[16,15,16,8,6,0],[21,15,21,7,1,0],[26,26,20,9,14,0],[44,44,17,22,21,0],[23,23,21,17,1,0],[25,25,18,9,8,0],[11,11,7,4,1,0],[12,12,9,11,4,0],[20,20,14,3,9,0],[25,16,25,6,2,0],[23,23,19,12,8,0],[13,13,8,9,0,0],[12,12,9,11,1,0],[24,15,24,3,5,0],[22,22,20,3,14,0],[26,26,16,5,11,0],[5,3,5,1,0,0],[22,15,22,1,0,0],[22,18,22,10,3,0],[21,21,18,6,3,0],[23,23,14,7,0,0],[17,17,14,8,1,0],[19,18,19,1,8,0],[18,11,18,0,0,0],[22,17,22,3,0,0],[25,25,24,10,1,0],[24,20,24,7,11,0],[15,15,14,10,4,0],[13,11,13,3,1,0],[15,15,15,12,1,0],[23,18,23,17,4,0],[26,19,26,7,2,0],[27,19,27,9,1,0],[15,15,9,3,0,0],[44,44,16,9,14,0],[23,15,23,6,1,0],[0,0,0,0,0,0],[32,17,32,10,0,0],[24,24,24,17,18,0],[20,16,20,8,0,0],[10,7,10,6,1,0],[20,20,12,14,3,0],[22,14,22,2,4,0],[40,40,18,14,20,0],[19,16,10,15,19,0],[7,6,4,7,1,0],[21,16,21,20,5,0],[26,17,26,9,0,0],[18,18,18,5,13,0],[19,11,19,4,4,0],[15,15,10,8,0,0],[21,15,21,3,0,0],[21,21,20,6,7,0],[28,24,28,7,2,0],[35,33,35,25,11,0],[87,87,19,11,16,0],[45,45,13,12,1,0],[73,73,41,24,14,0],[23,23,18,8,13,0],[22,19,22,11,1,0],[23,23,19,12,1,0],[10,10,6,2,0,0],[27,27,20,7,1,0],[28,15,28,0,0,0],[24,13,24,11,1,0],[9,9,7,4,5,0],[25,18,25,3,4,0],[17,15,17,9,15,0],[21,15,21,6,3,0],[32,32,14,14,7,0],[24,24,22,8,0,0],[40,40,18,17,11,0],[30,19,30,6,9,0],[100,14,100,23,12,0],[48,40,48,27,18,0],[19,18,19,5,2,0],[30,30,29,28,8,0],[21,21,6,3,1,0],[45,45,31,20,11,0],[46,46,34,9,9,0],[27,19,27,9,3,0],[31,21,31,5,3,0],[30,19,30,7,0,0],[16,9,16,5,2,0],[16,16,7,5,0,0],[25,23,25,2,1,0],[31,31,13,17,10,0],[25,16,25,10,1,0],[39,31,39,22,29,0],[70,70,46,47,30,0],[24,24,22,23,11,0],[49,49,8,33,8,0],[19,19,18,8,7,0],[32,32,24,17,7,0],[19,19,18,11,1,0],[11,11,3,4,3,0],[27,26,27,7,2,0],[27,19,27,7,3,0],[22,19,22,1,0,0],[40,40,15,13,1,0],[6,0,6,2,2,0],[2,2,1,2,1,0],[4,4,3,0,1,0],[0,0,0,0,0,0],[30,17,30,6,2,0],[27,18,27,5,1,0],[14,14,9,13,2,0],[11,11,10,8,0,0],[20,20,16,4,8,0],[25,25,19,11,6,0],[61,35,61,22,9,0],[100,26,100,24,14,0],[34,12,34,3,0,0],[13,9,13,5,4,0],[17,17,12,7,4,0],[25,18,25,10,1,0],[27,27,18,9,3,0],[25,22,25,4,4,0],[14,11,14,11,0,0],[11,11,6,11,0,0],[26,26,18,16,4,0],[22,18,22,8,3,0],[32,32,13,20,5,0],[11,9,11,0,0,0],[21,11,21,5,2,0],[14,14,11,10,0,0],[33,22,33,7,3,0],[22,17,22,11,5,0],[22,19,22,11,1,0],[10,10,7,5,0,0],[14,9,14,9,1,0],[15,12,15,6,13,0],[26,16,26,5,0,0],[24,21,24,6,3,0],[33,33,29,4,2,0],[13,11,13,2,5,0],[17,7,17,4,0,0],[26,11,26,0,0,0],[27,27,15,24,11,0],[28,22,28,5,1,0],[9,8,9,3,0,0],[14,10,14,1,0,0],[29,25,29,4,5,0],[15,15,15,0,13,0],[44,17,44,13,4,0],[16,16,16,15,1,0],[21,21,11,9,5,0],[13,13,8,7,2,0],[25,25,15,11,0,0],[19,17,19,3,9,0],[29,29,19,11,7,0],[20,19,20,2,4,0],[7,7,4,0,0,0],[25,11,25,3,1,0],[14,14,13,9,12,0],[35,35,20,16,2,0],[25,14,25,0,0,0],[20,20,16,16,4,0],[19,19,15,1,1,0],[16,14,16,8,1,0],[18,18,15,17,0,0],[20,20,19,10,4,0],[26,24,26,8,4,0],[14,10,14,7,2,0],[17,14,17,0,0,0],[26,9,26,0,0,0],[33,33,19,10,5,0],[60,60,40,19,9,0],[71,71,25,20,7,0],[70,70,18,29,4,0],[60,60,23,11,3,0],[44,44,41,1,0,0],[65,30,65,32,19,0],[91,26,91,17,21,0],[79,41,79,40,32,0],[23,23,16,9,6,0],[34,34,8,10,14,0],[23,17,12,23,4,0],[44,44,37,20,23,0],[23,23,8,1,0,0],[42,42,41,24,19,0],[15,10,15,2,1,0],[30,26,30,12,4,0],[21,21,19,12,4,0],[24,24,13,15,0,0],[8,7,1,8,0,0],[27,27,15,20,1,0],[15,12,15,6,1,0],[53,31,53,29,14,0],[59,59,55,38,23,0],[28,19,22,28,7,0],[53,53,19,12,10,0],[15,8,15,0,0,0],[20,20,19,10,6,0],[26,26,23,8,17,0],[43,43,21,11,0,0],[22,15,22,19,3,0],[22,22,7,1,0,0],[25,16,25,4,6,0],[23,18,23,6,1,0],[30,30,17,24,14,0],[23,23,19,10,2,0],[17,14,17,4,1,0],[44,13,44,21,3,0],[33,21,33,29,0,0],[23,23,19,19,4,0],[23,23,21,22,13,0],[11,7,11,0,0,0],[20,12,20,2,0,0],[21,21,14,11,4,0],[22,20,22,9,5,0],[24,15,24,6,0,0],[18,18,18,6,8,0],[11,9,11,3,0,0],[17,15,17,5,7,0],[34,12,34,0,0,0],[28,18,28,5,0,0],[13,10,13,0,0,0],[31,28,31,8,4,0],[14,12,14,4,0,0],[14,14,10,3,3,0],[19,15,19,15,0,0],[30,17,30,10,11,0],[28,14,28,2,0,0],[19,19,15,6,0,0],[15,15,15,1,2,0],[26,14,26,6,6,0],[26,17,26,6,0,0],[25,25,18,11,0,0],[24,13,24,0,0,0],[21,19,21,11,11,0],[8,8,3,5,0,0],[19,19,18,11,1,0],[30,15,30,4,0,0],[35,35,26,11,14,0],[28,13,28,7,0,0],[11,6,11,0,0,0],[10,9,10,1,4,0],[24,17,24,13,10,0],[27,20,27,10,1,0],[21,18,21,4,0,0],[23,23,18,5,4,0],[23,23,14,8,2,0],[41,41,16,7,0,0],[47,47,22,3,2,0],[22,21,22,7,0,0],[26,21,26,14,5,0],[18,16,18,8,0,0],[12,12,5,2,1,0],[25,13,25,3,0,0],[33,33,22,12,0,0],[23,15,23,6,5,0],[21,17,21,4,2,0],[15,15,14,2,0,0],[22,22,20,7,1,0],[22,22,17,3,4,0],[29,29,24,0,0,0],[24,15,24,4,1,0],[30,18,30,8,4,0],[13,13,10,0,5,0],[16,15,16,7,0,0],[23,23,22,12,0,0],[28,14,28,10,3,0],[24,18,24,6,1,0],[13,12,13,4,2,0],[20,18,13,3,20,0],[29,22,29,4,2,0],[28,19,28,15,2,0],[29,14,29,1,0,0],[19,16,19,2,6,0],[16,16,16,1,4,0],[45,45,19,9,0,0],[92,21,24,9,92,0],[60,47,36,23,60,0],[29,29,19,12,3,0],[18,18,13,8,3,0],[12,12,5,12,0,0],[6,2,0,6,6,0],[48,48,45,22,2,0],[20,20,16,7,0,0],[66,66,7,7,5,0],[81,81,20,26,14,0],[59,59,27,15,7,0],[60,60,41,12,9,0],[22,15,22,5,6,0],[19,19,7,5,0,0],[20,19,20,11,4,0],[30,28,17,30,9,0],[29,22,29,6,5,0],[66,66,46,47,8,0],[52,50,52,23,43,0],[32,32,29,7,0,0],[33,33,14,26,12,0],[19,17,19,12,7,0],[29,19,29,11,6,0],[8,8,7,0,0,0],[11,11,11,2,11,0],[28,22,28,5,1,0],[24,24,24,3,3,0],[24,24,18,2,1,0],[34,34,20,28,21,0],[20,20,8,5,8,0],[21,21,15,4,1,0],[24,24,19,16,3,0],[25,19,25,10,0,0],[37,23,37,15,6,0],[33,15,33,7,0,0],[19,19,8,6,0,0],[15,11,15,4,8,0],[27,19,27,9,3,0],[19,19,17,6,17,0],[27,27,15,8,9,0],[14,14,5,0,0,0],[15,13,15,0,0,0],[21,19,21,5,8,0],[20,15,20,6,2,0],[22,20,22,7,0,0],[32,32,23,19,6,0],[32,12,32,8,3,0],[18,18,13,5,5,0],[23,23,13,8,4,0],[29,25,29,4,3,0],[24,19,24,14,1,0],[24,19,24,5,6,0],[11,6,11,0,0,0],[22,14,22,3,1,0],[16,16,16,10,12,0],[32,17,32,3,1,0],[22,22,21,8,7,0],[25,17,25,11,1,0],[5,3,5,2,0,0],[24,18,12,4,24,0],[3,3,1,0,0,0],[19,19,15,11,8,0],[10,7,10,0,0,0],[22,19,22,4,2,0],[24,17,24,7,0,0],[25,16,25,5,0,0],[25,25,15,20,11,0],[21,21,21,8,5,0],[19,11,19,0,0,0],[17,13,17,4,1,0],[30,15,30,11,5,0],[23,22,23,11,1,0],[39,16,39,15,4,0],[17,6,17,0,0,0],[18,9,18,0,0,0],[18,15,18,12,3,0],[2,2,0,0,0,0],[37,29,37,21,0,0],[19,19,13,3,0,0],[24,17,24,13,1,0],[19,15,19,6,0,0],[16,16,15,9,0,0],[23,23,12,8,5,0],[23,17,23,10,6,0],[28,28,22,0,5,0],[19,7,19,0,0,0],[25,14,25,0,0,0],[23,18,23,5,2,0],[24,16,24,6,4,0],[23,19,23,13,2,0],[34,34,18,15,6,0],[13,13,5,11,1,0],[16,8,16,5,1,0],[28,13,28,10,4,0],[26,20,26,13,3,0],[25,25,21,16,11,0],[21,21,18,6,5,0],[4,4,0,0,0,0],[36,10,36,2,0,0],[58,45,58,6,3,0],[60,60,25,34,13,0],[50,20,21,50,19,0],[100,33,29,100,16,0],[56,56,31,16,13,0],[19,19,12,4,1,0],[24,24,15,9,9,0],[32,23,32,9,6,0],[43,43,36,30,11,0],[26,21,26,3,8,0],[22,22,22,6,7,0],[25,22,25,4,5,0],[21,21,17,14,8,0],[30,30,22,17,1,0],[28,19,28,7,0,0],[27,19,27,3,0,0],[18,18,15,10,0,0],[16,16,9,0,6,0],[26,13,26,4,0,0],[73,73,41,30,38,0],[28,28,22,23,4,0],[45,45,28,19,9,0],[91,91,30,43,4,0],[67,67,17,28,12,0],[72,72,66,34,29,0],[21,21,14,3,3,0],[25,25,18,4,1,0],[40,40,26,19,0,0],[10,10,10,7,0,0],[19,15,19,10,15,0],[28,16,28,3,3,0],[19,18,19,10,14,0],[33,33,29,10,13,0],[15,8,15,7,6,0],[17,11,17,6,12,0],[30,28,10,21,30,0],[35,24,23,35,6,0],[26,20,26,3,0,0],[10,10,7,8,0,0],[25,25,16,5,0,0],[20,20,15,10,5,0],[23,21,23,6,0,0],[22,18,22,13,0,0],[21,21,16,4,6,0],[17,17,14,8,0,0],[25,15,25,17,2,0],[27,18,27,6,1,0],[24,16,24,6,6,0],[26,21,26,11,3,0],[15,15,14,7,4,0],[18,18,13,6,2,0],[56,24,56,21,1,0],[100,20,100,23,15,0],[34,22,34,6,6,0],[24,18,24,12,0,0],[19,19,13,3,3,0],[24,24,9,2,5,0],[18,15,18,12,0,0],[26,26,14,1,11,0],[28,22,28,8,5,0],[25,19,25,6,7,0],[19,19,10,4,5,0],[15,10,15,4,3,0],[19,17,19,6,0,0],[29,17,29,9,3,0],[33,33,24,18,3,0],[28,21,28,8,0,0],[20,13,20,7,3,0],[6,6,5,4,2,0],[26,15,26,1,1,0],[30,15,30,0,0,0],[28,24,28,6,2,0],[23,23,22,14,8,0],[39,39,13,4,0,0],[30,14,12,30,9,0],[23,20,23,10,11,0],[22,22,21,1,12,0],[27,10,27,7,2,0],[19,16,19,7,5,0],[16,16,14,8,3,0],[21,21,5,5,0,0],[16,16,16,6,9,0],[20,19,17,20,0,0],[31,16,31,3,0,0],[14,14,13,8,8,0],[36,36,12,11,5,0],[14,14,10,7,0,0],[24,19,24,10,11,0],[21,21,21,16,2,0],[18,16,18,10,1,0],[13,13,11,6,0,0],[15,15,5,1,4,0],[22,22,14,14,4,0],[22,15,22,13,5,0],[23,21,23,7,5,0],[20,20,19,12,1,0],[11,6,6,11,0,0],[16,16,9,9,1,0],[21,17,21,6,3,0],[22,21,22,14,12,0],[45,45,27,5,5,0],[26,26,24,17,1,0],[30,8,30,14,1,0],[100,26,100,28,3,0],[57,57,33,31,26,0],[25,25,22,8,6,0],[30,30,26,14,10,0],[29,29,20,14,2,0],[19,13,19,1,0,0],[37,37,27,30,21,0],[21,14,21,9,0,0],[41,41,23,22,9,0],[25,25,21,7,3,0],[27,27,21,6,3,0],[17,17,16,11,3,0],[16,16,10,3,2,0],[22,22,16,14,1,0],[24,24,19,12,4,0],[18,18,15,11,4,0],[57,42,34,57,23,0],[29,29,16,5,3,0],[54,54,52,23,15,0],[36,30,36,5,2,0],[39,39,28,31,27,0],[43,27,43,16,21,0],[22,18,22,2,3,0],[17,17,15,1,1,0],[15,15,13,10,2,0],[27,27,17,8,0,0],[31,31,16,9,20,0],[16,16,16,7,0,0],[17,15,17,4,1,0],[18,13,18,4,0,0],[81,81,33,39,24,0],[74,74,20,24,12,0],[70,70,37,22,30,0],[19,19,1,0,0,0],[3,3,0,1,1,0],[40,18,40,0,0,0],[26,14,26,6,3,0],[34,27,34,13,5,0],[23,20,23,7,0,0],[20,10,20,5,0,0],[31,16,31,11,4,0],[51,23,51,17,2,0],[38,33,33,36,38,0],[20,20,14,12,0,0],[26,26,13,5,0,0],[10,10,10,4,3,0],[24,21,24,11,11,0],[28,16,28,0,0,0],[21,19,21,12,3,0],[66,57,66,27,12,0],[100,100,10,15,4,0],[84,84,30,27,5,0],[100,100,55,30,81,0],[100,100,37,34,97,0],[100,100,34,16,100,0],[100,100,47,35,100,0],[100,100,34,20,100,0],[100,100,45,37,96,0],[100,100,35,28,100,0],[100,100,38,49,100,0],[100,100,43,37,100,0],[100,100,44,25,100,0],[100,100,32,92,32,0],[100,100,78,70,27,0],[100,100,100,34,57,0],[100,100,81,27,32,0],[100,100,47,28,41,0],[100,100,29,46,69,0],[100,100,41,100,38,0],[100,100,41,100,39,0],[100,100,44,100,41,0],[100,100,56,100,42,0],[100,100,31,100,25,0],[100,100,35,74,59,0],[100,70,63,35,100,0],[100,39,100,76,61,0],[100,52,100,100,38,0],[100,38,100,100,39,0],[100,39,100,100,35,0],[100,35,100,78,53,0],[100,49,100,33,100,0],[100,36,100,71,65,0],[88,62,88,28,31,0],[100,24,100,29,10,0],[100,15,100,16,8,0],[60,58,60,34,11,0],[59,35,32,59,52,0],[100,71,100,48,50,0],[100,76,100,51,43,0],[78,62,78,32,50,0],[100,20,22,38,100,0],[87,63,87,56,18,0],[100,84,100,77,67,0],[62,62,50,39,23,0],[26,26,22,3,0,0],[18,18,16,8,1,0],[19,16,19,2,4,0],[39,39,28,12,0,0],[77,32,77,29,24,0],[24,23,24,13,22,0],[100,25,28,8,100,0],[37,37,31,22,33,0],[23,23,15,14,12,0],[60,60,35,16,11,0],[94,29,94,33,11,0]],"renderLoad":[[272,41],[288,80],[405,33],[1273,39],[1290,37],[1407,28],[2276,45],[2293,33],[2410,30],[3278,47],[3295,35],[3412,40],[4267,38],[4281,39],[4298,88],[4415,44],[4432,32],[5250,97],[5267,21],[5284,7],[5350,41],[5367,51],[5384,37],[6269,30],[6286,34],[6319,43],[6453,43],[7272,26],[7288,28],[7322,32],[7439,83],[7456,70],[8274,26],[8291,19],[8324,32],[8442,35],[9278,27],[9295,20],[9328,43],[9444,33],[10266,32],[10280,18],[10330,78],[10446,34],[11282,31],[11298,28],[11349,30],[11466,75],[12284,36],[12301,28],[12351,41],[12468,36],[12485,37],[13287,34],[13303,62]]} -------------------------------------------------------------------------------- /dataset/workload/osborn/raw/README.md: -------------------------------------------------------------------------------- 1 | # 本文件夹负载序列原始数据说明 2 | 3 | ## 采集systrace 4 | 5 | 1. 配置手机的HMP和CPU调速器 6 | 1. `sched_boost` = 1 7 | 2. 大核心的CPU调速器 = `performance` 8 | 2. 开启设备的ADB 9 | 3. 点击[这里](https://developer.android.com/studio/releases/platform-tools)下载`platform-tools`,配置完成后执行 10 | 11 | ```bash 12 | python systrace.py -t 30 input idle view -o xxxxx.html 13 | ``` 14 | ## 采集设备 15 | 16 | 坚果 Pro 2 17 | sdm660 A73 x 4 @2208mhz 18 | 同频性能:1638(A53为1024) 19 | 20 | ## 本文件夹采集的负载情景 21 | 22 | 每段大约30s 23 | 24 | - 微信 朋友圈 25 | - 微信 打字 26 | - 微信 选择图片 27 | - 微信 公众号 28 | - 微信 小程序 29 | - QQ 打字 滑动 30 | - QQ 空间动态 31 | - bili 信息流 32 | - bili 1080+弹幕 33 | - share 信息流 34 | - 贴吧 wp7吧 35 | - 酷安 首页 36 | - 美团 搜索饭店 37 | - via 浏览apple官网 38 | - 七日之都 1-1 39 | - 七日之都 小boss 40 | - 淘宝 选择小米移动电源 41 | - 闲鱼 搜索游戏主机 42 | - 百度地图 搜索世纪大道 43 | - Twitter 信息流 44 | - 频繁多任务切换 45 | -------------------------------------------------------------------------------- /dataset/workload/osborn/raw/info.json: -------------------------------------------------------------------------------- 1 | { 2 | "device": "坚果 Pro 2", 3 | "date": "2019-02-26T15:00:00.000Z", 4 | "efficiency": 1638, 5 | "freq": 2208, 6 | "onscreen": { 7 | "comment": "用于评估使用时性能和续航,在仿真器内会顺序执行,百度地图和微信小程序满负载比重太高,去除", 8 | "loadSeq": [ 9 | "bili-danmu.html", 10 | "bili-feed.html", 11 | "coolapk-feed.html", 12 | "game-7days-city-boss.html", 13 | "game-7days-city-regular.html", 14 | "meituan-explore.html", 15 | "qq-chat.html", 16 | "qq-qzone.html", 17 | "share-feed.html", 18 | "taobao-international-explore.html", 19 | "task-switch.html", 20 | "tieba-lite.html", 21 | "twitter-feed.html", 22 | "via-iphonexs-intro.html", 23 | "wx-chat.html", 24 | "wx-gongzhonghao.html", 25 | "wx-moment.html", 26 | "wx-select-pic.html", 27 | "xianyu-search.html", 28 | "bili-download.html" 29 | ] 30 | }, 31 | "offscreen": { 32 | "comment": "用于评估待机时续航,在仿真器内会顺序执行,注意需要bili-download.html先拉高负载再进入待机检查,来避免借助过高的above绕过待机耗电检查即使高频的targetload很低很难降频省电", 33 | "loadSeq": [ 34 | "idle-music.html" 35 | ] 36 | } 37 | } -------------------------------------------------------------------------------- /media/sim.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yc9559/wipe-v2/14059cc82ca0527fe61d1cd0b1d2f9a2cff3b1be/media/sim.png -------------------------------------------------------------------------------- /source/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "cpumodel.h" 6 | #include "dump.h" 7 | #include "json.hpp" 8 | #include "openga_helper.h" 9 | #include "sim.hpp" 10 | #include "workload.h" 11 | 12 | template 13 | void DoOpt(Soc &soc, const Workload &work, const Workload &idle) { 14 | auto nsga3_opt = OpengaAdapter(&soc, &work, &idle, "./conf.json"); 15 | auto ret = nsga3_opt.Optimize(); 16 | auto dumper = Dumper(soc, "./output/"); 17 | dumper.DumpToTXT(ret); 18 | dumper.DumpToCSV(ret); 19 | dumper.DumpToShellScript(ret); 20 | dumper.DumpToUperfJson(ret); 21 | } 22 | 23 | int main() { 24 | nlohmann::json j; 25 | { 26 | std::ifstream ifs("./conf.json"); 27 | if (!ifs.good()) { 28 | using namespace std; 29 | cout << "WIPE-v2 config file access ERROR: " 30 | << "./conf.json" << endl; 31 | throw std::runtime_error("file access error"); 32 | } 33 | ifs >> j; 34 | } 35 | 36 | auto todo_models = j["todoModels"]; 37 | auto workload = j["mergedWorkload"]; 38 | auto idleload = j["idleWorkload"]; 39 | auto use_uperf = j["useUperf"]; 40 | 41 | Workload work(workload); 42 | Workload idle(idleload); 43 | 44 | for (const auto &model : todo_models) { 45 | Soc soc(model); 46 | if (use_uperf) { 47 | if (soc.GetSchedType() == Soc::kWalt) { 48 | DoOpt(soc, work, idle); 49 | } 50 | if (soc.GetSchedType() == Soc::kPelt) { 51 | DoOpt(soc, work, idle); 52 | } 53 | } else { 54 | if (soc.GetSchedType() == Soc::kWalt) { 55 | DoOpt(soc, work, idle); 56 | } 57 | if (soc.GetSchedType() == Soc::kPelt) { 58 | DoOpt(soc, work, idle); 59 | } 60 | } 61 | } 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /source/opt/openga_helper.cpp: -------------------------------------------------------------------------------- 1 | #include "openga_helper.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "interactive.h" 8 | #include "json.hpp" 9 | 10 | template 11 | OpengaAdapter::OpengaAdapter(Soc *soc, const Workload *workload, const Workload *idleload, 12 | const std::string &ga_cfg_file) 13 | : soc_(soc), workload_(workload), idleload_(idleload) { 14 | ParseCfgFile(ga_cfg_file); 15 | InitDefaultScore(); 16 | }; 17 | 18 | template 19 | void OpengaAdapter::ParseCfgFile(const std::string &ga_cfg_file) { 20 | nlohmann::json j; 21 | { 22 | std::ifstream ifs(ga_cfg_file); 23 | if (!ifs.good()) { 24 | using namespace std; 25 | cout << "GA config file access ERROR: " << ga_cfg_file << endl; 26 | throw std::runtime_error("file access error"); 27 | } 28 | ifs >> j; 29 | } 30 | 31 | // 解析NSGA3相关参数 32 | auto p = j["gaParameter"]; 33 | ga_cfg_.population = p["population"]; 34 | ga_cfg_.generation_max = p["generationMax"]; 35 | ga_cfg_.crossover_fraction = p["crossoverFraction"]; 36 | ga_cfg_.mutation_rate = p["mutationRate"]; 37 | ga_cfg_.eta = p["eta"]; 38 | ga_cfg_.thread_num = p["threadNum"]; 39 | ga_cfg_.random_seed = p["randomSeed"]; 40 | 41 | // 解析结果的分数限制和可调占比 42 | auto misc = j["miscSettings"]; 43 | misc_.idle_fraction = misc["ga.cost.batteryScore.idleFraction"]; 44 | misc_.work_fraction = misc["ga.cost.batteryScore.workFraction"]; 45 | misc_.idle_lasting_min = misc["ga.cost.limit.idleLastingMin"]; 46 | misc_.performance_max = misc["ga.cost.limit.performanceMax"]; 47 | 48 | sim_misc_.working_base_mw = misc["sim.power.workingBase_mw"]; 49 | sim_misc_.idle_base_mw = misc["sim.power.idleBase_mw"]; 50 | 51 | rank_misc_.common_fraction = misc["eval.perf.commonFraction"]; 52 | rank_misc_.render_fraction = misc["eval.perf.renderFraction"]; 53 | rank_misc_.perf_partition_len = misc["eval.perf.partitionLen"]; 54 | rank_misc_.batt_partition_len = misc["eval.power.partitionLen"]; 55 | rank_misc_.seq_lag_l1 = misc["eval.perf.seqLagL1"]; 56 | rank_misc_.seq_lag_l2 = misc["eval.perf.seqLagL2"]; 57 | rank_misc_.seq_lag_max = misc["eval.perf.seqLagMax"]; 58 | rank_misc_.seq_lag_l0_scale = misc["eval.perf.seqLagL0Scale"]; 59 | rank_misc_.seq_lag_l1_scale = misc["eval.perf.seqLagL1Scale"]; 60 | rank_misc_.seq_lag_l2_scale = misc["eval.perf.seqLagL2Scale"]; 61 | rank_misc_.enough_penalty = misc["eval.perf.enoughPenalty"]; 62 | rank_misc_.complexity_fraction = misc["eval.complexityFraction"]; 63 | 64 | // 解析参数搜索空间范围 65 | ParamDescCfg desc_cfg; 66 | 67 | auto get_range = [j](const std::string &key) { 68 | ParamDescElement el; 69 | el.range_start = j["parameterRange"][key]["min"]; 70 | el.range_end = j["parameterRange"][key]["max"]; 71 | return el; 72 | }; 73 | 74 | desc_cfg.above_hispeed_delay = get_range("above_hispeed_delay"); 75 | desc_cfg.go_hispeed_load = get_range("go_hispeed_load"); 76 | desc_cfg.max_freq_hysteresis = get_range("max_freq_hysteresis"); 77 | desc_cfg.min_sample_time = get_range("min_sample_time"); 78 | desc_cfg.target_loads = get_range("target_loads"); 79 | desc_cfg.sched_downmigrate = get_range("sched_downmigrate"); 80 | desc_cfg.sched_upmigrate = get_range("sched_upmigrate"); 81 | desc_cfg.sched_ravg_hist_size = get_range("sched_ravg_hist_size"); 82 | desc_cfg.sched_window_stats_policy = get_range("sched_window_stats_policy"); 83 | desc_cfg.sched_boost = get_range("sched_boost"); 84 | desc_cfg.timer_rate = get_range("timer_rate"); 85 | desc_cfg.input_duration = get_range("input_duration"); 86 | desc_cfg.load_avg_period_ms = get_range("load_avg_period_ms"); 87 | desc_cfg.down_threshold = get_range("down_threshold"); 88 | desc_cfg.up_threshold = get_range("up_threshold"); 89 | desc_cfg.boost = get_range("boost"); 90 | 91 | InitParamDesc(desc_cfg); 92 | } 93 | 94 | template 95 | void OpengaAdapter::InitParamSeq(ParamSeq &p, const RandomFunc &rnd01) { 96 | p.reserve(param_len_); 97 | for (int i = 0; i < param_len_; ++i) { 98 | p.push_back(rnd01()); 99 | } 100 | } 101 | 102 | // mutPolynomialBounded 103 | // Polynomial mutation as implemented in original NSGA-II algorithm in C by Deb. 104 | template 105 | ParamSeq OpengaAdapter::Mutate(const ParamSeq &X_base, const RandomFunc &rnd01, double shrink_scale) { 106 | // 假设X1,X2等长 107 | const int size = X_base.size(); 108 | const double eta = ga_cfg_.eta; 109 | const double eta_1 = eta + 1.0; 110 | const double mut_pow = 1.0 / eta_1; 111 | ParamSeq ret(size); 112 | 113 | for (int idx = 0; idx < size; ++idx) { 114 | if (rnd01() >= 0.5) { 115 | ret[idx] = X_base[idx]; 116 | continue; 117 | } 118 | 119 | const double delta_1 = X_base[idx]; 120 | const double delta_2 = 1.0 - X_base[idx]; 121 | const double rnd = rnd01(); 122 | double delta_q, val; 123 | 124 | if (rnd < 0.5) { 125 | val = 2.0 * rnd + (1.0 - 2.0 * rnd) * std::pow(1.0 - delta_1, eta_1); 126 | delta_q = std::pow(val, mut_pow) - 1.0; 127 | } else { 128 | val = 2.0 * (1.0 - rnd) + 2.0 * (rnd - 0.5) * std::pow(1.0 - delta_2, eta_1); 129 | delta_q = 1.0 - std::pow(val, mut_pow); 130 | } 131 | 132 | ret[idx] = std::min(std::max(X_base[idx] + delta_q, 0.0), 1.0); 133 | } 134 | return ret; 135 | } 136 | 137 | // cxSimulatedBinaryBounded 138 | // Executes a simulated binary crossover that modify in-place the input individuals. The simulated binary crossover 139 | // expects :term:`sequence` individuals of floating point numbers 140 | template 141 | ParamSeq OpengaAdapter::Crossover(const ParamSeq &X1, const ParamSeq &X2, const RandomFunc &rnd01) { 142 | // 假设X1,X2等长 143 | const int size = X1.size(); 144 | const double eta = ga_cfg_.eta; 145 | const double eta_1 = eta + 1.0; 146 | ParamSeq ret(size); 147 | 148 | for (int idx = 0; idx < size; ++idx) { 149 | if (rnd01() >= 0.5) { 150 | ret[idx] = X1[idx]; 151 | continue; 152 | } 153 | if (fabs(X1[idx] - X2[idx]) < 0.0) { 154 | ret[idx] = X2[idx]; 155 | continue; 156 | } 157 | 158 | const double x1 = std::min(X1[idx], X2[idx]); 159 | const double x2 = std::max(X1[idx], X2[idx]); 160 | const double rnd = rnd01(); 161 | const double x2_x1 = x2 - x1; 162 | double beta_q; 163 | 164 | double beta = 1.0 + (2.0 * x1 / x2_x1); 165 | double alpha = 2.0 - std::pow(beta, -eta_1); 166 | if (rnd <= 1.0 / alpha) { 167 | beta_q = std::pow(rnd * alpha, 1.0 / eta_1); 168 | } else { 169 | beta_q = std::pow(1.0 / (2.0 - rnd * alpha), 1.0 / eta_1); 170 | } 171 | 172 | double c1 = 0.5 * (x1 + x2 - beta_q * x2_x1); 173 | 174 | beta = 1.0 + (2.0 * (1.0 - x2) / x2_x1); 175 | alpha = 2.0 - std::pow(beta, -eta_1); 176 | if (rnd <= 1.0 / alpha) { 177 | beta_q = std::pow(rnd * alpha, 1.0 / eta_1); 178 | } else { 179 | beta_q = std::pow(1.0 / (2.0 - rnd * alpha), 1.0 / eta_1); 180 | } 181 | 182 | double c2 = 0.5 * (x1 + x2 + beta_q * x2_x1); 183 | 184 | c1 = std::min(std::max(c1, 0.0), 1.0); 185 | c2 = std::min(std::max(c2, 0.0), 1.0); 186 | 187 | if (rnd01() <= 0.5) { 188 | ret[idx] = c2; 189 | } else { 190 | ret[idx] = c1; 191 | } 192 | } 193 | return ret; 194 | } 195 | 196 | template 197 | void OpengaAdapter::MO_report_generation(int generation_number, 198 | const EA::GenerationType &last_generation, 199 | const std::vector & pareto_front) { 200 | return; 201 | } 202 | 203 | template 204 | bool OpengaAdapter::EvalParamSeq(const ParamSeq ¶m_seq, MiddleCost &result) { 205 | typename SimType::Tunables t = TranslateParamSeq(param_seq); 206 | 207 | SimResultPack rp; 208 | rp.onscreen.capacity.reserve(workload_->windowed_load_.size()); 209 | rp.onscreen.power.reserve(workload_->windowed_load_.size()); 210 | 211 | SimType sim(t, sim_misc_); 212 | sim.Run(*workload_, *idleload_, *soc_, &rp); 213 | Rank rank(default_score_, rank_misc_); 214 | auto score = rank.Eval(*workload_, *idleload_, rp, *soc_, false); 215 | 216 | result.c1 = score.performance; 217 | result.c2 = score.battery_life; 218 | result.c3 = score.idle_lasting; 219 | 220 | bool pass = (score.idle_lasting > misc_.idle_lasting_min) && (score.performance < misc_.performance_max); 221 | return pass; 222 | } 223 | 224 | template 225 | void OpengaAdapter::InitDefaultScore() { 226 | typename SimType::Tunables t = GenerateDefaultTunables(); 227 | Rank::Score s = {1.0, 1.0, 1.0}; 228 | 229 | SimResultPack rp; 230 | rp.onscreen.capacity.reserve(workload_->windowed_load_.size()); 231 | rp.onscreen.power.reserve(workload_->windowed_load_.size()); 232 | 233 | SimType sim(t, sim_misc_); 234 | sim.Run(*workload_, *idleload_, *soc_, &rp); 235 | Rank rank(s, rank_misc_); 236 | default_score_ = rank.Eval(*workload_, *idleload_, rp, *soc_, true); 237 | } 238 | 239 | template 240 | std::vector::Result> OpengaAdapter::Optimize(void) { 241 | using namespace std::placeholders; 242 | EA::Chronometer timer; 243 | timer.tic(); 244 | 245 | GA_Type ga_obj(ga_cfg_.random_seed); 246 | ga_obj.problem_mode = EA::GA_MODE::NSGA_III; 247 | ga_obj.verbose = false; 248 | ga_obj.population = ga_cfg_.population; 249 | ga_obj.generation_max = ga_cfg_.generation_max; 250 | ga_obj.calculate_MO_objectives = std::bind(&OpengaAdapter::CalcMultiObjectives, this, _1); 251 | ga_obj.init_genes = std::bind(&OpengaAdapter::InitParamSeq, this, _1, _2); 252 | ga_obj.eval_solution = std::bind(&OpengaAdapter::EvalParamSeq, this, _1, _2); 253 | ga_obj.mutate = std::bind(&OpengaAdapter::Mutate, this, _1, _2, _3); 254 | ga_obj.crossover = std::bind(&OpengaAdapter::Crossover, this, _1, _2, _3); 255 | ga_obj.MO_report_generation = std::bind(&OpengaAdapter::MO_report_generation, this, _1, _2, _3); 256 | ga_obj.crossover_fraction = ga_cfg_.crossover_fraction; 257 | ga_obj.mutation_rate = ga_cfg_.mutation_rate; 258 | ga_obj.dynamic_threading = false; 259 | ga_obj.multi_threading = false; 260 | ga_obj.N_threads = ga_cfg_.thread_num; 261 | ga_obj.idle_delay_us = 1; // switch between threads quickly 262 | 263 | if (ga_cfg_.thread_num > 1) { 264 | ga_obj.multi_threading = true; 265 | ga_obj.dynamic_threading = true; 266 | } 267 | 268 | std::cout << "\nTarget: " << soc_->name_ << std::endl; 269 | std::cout << "Chromosome length: " << param_len_ << std::endl; 270 | 271 | ga_obj.solve(); 272 | 273 | std::cout << "\nOptimized in " << timer.toc() << " seconds." << std::endl; 274 | 275 | std::vector ret; 276 | ret.reserve(ga_obj.last_generation.fronts[0].size()); 277 | auto paretofront_indices = ga_obj.last_generation.fronts[0]; 278 | for (const auto &i : paretofront_indices) { 279 | Result r; 280 | const auto &chromosome = ga_obj.last_generation.chromosomes[i]; 281 | r.tunable = TranslateParamSeq(chromosome.genes); 282 | r.score.performance = chromosome.middle_costs.c1; 283 | r.score.battery_life = chromosome.middle_costs.c2; 284 | r.score.idle_lasting = chromosome.middle_costs.c3; 285 | ret.push_back(r); 286 | } 287 | 288 | return ret; 289 | } 290 | 291 | int Quantify(double ratio, const ParamDescElement &desc) { 292 | return (desc.range_start + std::round((desc.range_end - desc.range_start) * ratio)); 293 | } 294 | 295 | int QuatFreqParam(double ratio, const Cluster &cluster, const ParamDescElement &desc) { 296 | return cluster.freq_floor_to_opp(Quantify(ratio, desc)); 297 | } 298 | 299 | int QuatLoadParam(double ratio, const ParamDescElement &desc) { 300 | int target_load = Quantify(ratio, desc); 301 | // 减少targetload没必要的参数档位,降低参数复杂度 302 | // if (target_load > 15 && target_load < 85) { 303 | // target_load = target_load >> 2 << 2; 304 | // } 305 | return target_load; 306 | } 307 | 308 | int QuatLargeParam(double ratio, int step, const ParamDescElement &desc) { 309 | return (Quantify(ratio, desc) / step) * step; 310 | } 311 | 312 | template 313 | void DefineBlock(ParamDesc &desc, const ParamDescCfg &p, const Soc *soc) { 314 | return; 315 | } 316 | 317 | template 318 | T TranslateBlock(ParamSeq::const_iterator &it_seq, ParamDesc::const_iterator &it_desc, const Soc *soc) { 319 | return T(); 320 | } 321 | 322 | template <> 323 | void DefineBlock>(ParamDesc &desc, const ParamDescCfg &p, const Soc *soc) { 324 | for (const auto &cluster : soc->clusters_) { 325 | ParamDescElement hispeed_freq_desc = {cluster.model_.min_freq, cluster.model_.max_freq}; 326 | desc.push_back(hispeed_freq_desc); 327 | desc.push_back(p.go_hispeed_load); 328 | desc.push_back(p.min_sample_time); 329 | desc.push_back(p.max_freq_hysteresis); 330 | 331 | int n_opp = cluster.model_.opp_model.size(); 332 | int n_above = std::min(ABOVE_DELAY_MAX_LEN, n_opp); 333 | int n_targetloads = std::min(TARGET_LOAD_MAX_LEN, n_opp); 334 | 335 | for (int i = 0; i < n_above; ++i) { 336 | desc.push_back(p.above_hispeed_delay); 337 | } 338 | for (int i = 0; i < n_targetloads; ++i) { 339 | desc.push_back(p.target_loads); 340 | } 341 | } 342 | } 343 | 344 | template <> 345 | GovernorTs TranslateBlock(ParamSeq::const_iterator &it_seq, ParamDesc::const_iterator &it_desc, 346 | const Soc *soc) { 347 | GovernorTs t; 348 | 349 | int idx = 0; 350 | for (const auto &cluster : soc->clusters_) { 351 | t.t[idx].hispeed_freq = QuatFreqParam(*it_seq++, cluster, *it_desc++); 352 | t.t[idx].go_hispeed_load = QuatLoadParam(*it_seq++, *it_desc++); 353 | t.t[idx].min_sample_time = Quantify(*it_seq++, *it_desc++); 354 | t.t[idx].max_freq_hysteresis = Quantify(*it_seq++, *it_desc++); 355 | 356 | int n_opp = cluster.model_.opp_model.size(); 357 | int n_above = std::min(ABOVE_DELAY_MAX_LEN, n_opp); 358 | int n_targetloads = std::min(TARGET_LOAD_MAX_LEN, n_opp); 359 | 360 | for (int i = 0; i < n_above; ++i) { 361 | t.t[idx].above_hispeed_delay[i] = Quantify(*it_seq++, *it_desc++); 362 | } 363 | for (int i = 0; i < n_targetloads; ++i) { 364 | t.t[idx].target_loads[i] = QuatLoadParam(*it_seq++, *it_desc++); 365 | } 366 | idx++; 367 | } 368 | 369 | // 时长类参数取整到一个timer_rate 370 | idx = 0; 371 | for (const auto &cluster : soc->clusters_) { 372 | auto & tunable = t.t[idx]; 373 | double timer_quantum = 2; // timer_rate 固定为20ms 374 | 375 | tunable.min_sample_time = std::max(1.0, std::round(tunable.min_sample_time / timer_quantum)); 376 | tunable.max_freq_hysteresis = std::max(1.0, std::round(tunable.max_freq_hysteresis / timer_quantum)); 377 | 378 | int n_opp = cluster.model_.opp_model.size(); 379 | int n_above = std::min(ABOVE_DELAY_MAX_LEN, n_opp); 380 | 381 | for (int i = 0; i < n_above; ++i) { 382 | tunable.above_hispeed_delay[i] = std::max(1.0, std::round(tunable.above_hispeed_delay[i] / timer_quantum)); 383 | } 384 | idx++; 385 | } 386 | 387 | return std::move(t); 388 | } 389 | 390 | template <> 391 | void DefineBlock(ParamDesc &desc, const ParamDescCfg &p, const Soc *soc) { 392 | desc.push_back(p.sched_downmigrate); 393 | desc.push_back(p.sched_upmigrate); 394 | desc.push_back(p.sched_ravg_hist_size); 395 | desc.push_back(p.sched_window_stats_policy); 396 | desc.push_back(p.sched_boost); 397 | desc.push_back(p.timer_rate); 398 | } 399 | 400 | template <> 401 | WaltHmp::Tunables TranslateBlock(ParamSeq::const_iterator &it_seq, ParamDesc::const_iterator &it_desc, const Soc *soc) { 402 | WaltHmp::Tunables t; 403 | t.sched_downmigrate = QuatLoadParam(*it_seq++, *it_desc++); 404 | t.sched_upmigrate = QuatLoadParam(*it_seq++, *it_desc++); 405 | t.sched_upmigrate = std::max(t.sched_downmigrate, t.sched_upmigrate); 406 | t.sched_ravg_hist_size = Quantify(*it_seq++, *it_desc++); 407 | t.sched_window_stats_policy = Quantify(*it_seq++, *it_desc++); 408 | t.sched_boost = Quantify(*it_seq++, *it_desc++); 409 | t.timer_rate = Quantify(*it_seq++, *it_desc++); 410 | // sdm625和sdm820使用平衡型负载迁移 411 | if (soc->clusters_.size() < 2 || soc->clusters_[soc->GetLittleClusterIdx()].model_.core_num == 2) { 412 | t.sched_downmigrate = 45; 413 | t.sched_upmigrate = 45; 414 | } 415 | return std::move(t); 416 | } 417 | 418 | template <> 419 | void DefineBlock(ParamDesc &desc, const ParamDescCfg &p, const Soc *soc) { 420 | desc.push_back(p.down_threshold); 421 | desc.push_back(p.up_threshold); 422 | desc.push_back(p.load_avg_period_ms); 423 | desc.push_back(p.boost); 424 | desc.push_back(p.timer_rate); 425 | } 426 | 427 | template <> 428 | PeltHmp::Tunables TranslateBlock(ParamSeq::const_iterator &it_seq, ParamDesc::const_iterator &it_desc, const Soc *soc) { 429 | PeltHmp::Tunables t; 430 | t.down_threshold = Quantify(*it_seq++, *it_desc++); 431 | t.up_threshold = Quantify(*it_seq++, *it_desc++); 432 | t.up_threshold = std::max(t.down_threshold, t.up_threshold); 433 | t.load_avg_period_ms = Quantify(*it_seq++, *it_desc++); 434 | t.boost = Quantify(*it_seq++, *it_desc++); 435 | t.timer_rate = Quantify(*it_seq++, *it_desc++); 436 | return std::move(t); 437 | } 438 | 439 | template <> 440 | void DefineBlock(ParamDesc &desc, const ParamDescCfg &p, const Soc *soc) { 441 | for (const auto &cluster : soc->clusters_) { 442 | ParamDescElement input_freq = {cluster.model_.min_freq, cluster.model_.max_freq}; 443 | desc.push_back(input_freq); 444 | } 445 | desc.push_back(p.input_duration); 446 | } 447 | 448 | template <> 449 | InputBoostWalt::Tunables TranslateBlock(ParamSeq::const_iterator &it_seq, ParamDesc::const_iterator &it_desc, 450 | const Soc *soc) { 451 | InputBoostWalt::Tunables t; 452 | 453 | int idx = 0; 454 | for (const auto &cluster : soc->clusters_) 455 | t.boost_freq[idx++] = QuatFreqParam(*it_seq++, cluster, *it_desc++); 456 | t.duration_quantum = QuatLargeParam(*it_seq++, 10, *it_desc++); 457 | 458 | return std::move(t); 459 | } 460 | 461 | template <> 462 | void DefineBlock(ParamDesc &desc, const ParamDescCfg &p, const Soc *soc) { 463 | for (const auto &cluster : soc->clusters_) { 464 | ParamDescElement input_freq = {cluster.model_.min_freq, cluster.model_.max_freq}; 465 | desc.push_back(input_freq); 466 | } 467 | desc.push_back(p.input_duration); 468 | } 469 | 470 | template <> 471 | InputBoostPelt::Tunables TranslateBlock(ParamSeq::const_iterator &it_seq, ParamDesc::const_iterator &it_desc, 472 | const Soc *soc) { 473 | InputBoostPelt::Tunables t; 474 | 475 | int idx = 0; 476 | for (const auto &cluster : soc->clusters_) 477 | t.boost_freq[idx++] = QuatFreqParam(*it_seq++, cluster, *it_desc++); 478 | t.duration_quantum = QuatLargeParam(*it_seq++, 10, *it_desc++); 479 | 480 | return std::move(t); 481 | } 482 | 483 | template <> 484 | void DefineBlock(ParamDesc &desc, const ParamDescCfg &p, const Soc *soc) { 485 | for (const auto &cluster : soc->clusters_) { 486 | // 最大频率不能限制太多,否则影响突发性能,选择0.7*最大主频和1.2g较高的值 487 | int max_freq_floor = 0.7 * cluster.model_.max_freq; 488 | max_freq_floor = std::min(std::max(1200, max_freq_floor), cluster.model_.max_freq); 489 | auto min_range = ParamDescElement{cluster.model_.min_freq, cluster.model_.max_freq}; 490 | auto max_range = ParamDescElement{max_freq_floor, cluster.model_.max_freq}; 491 | desc.push_back(min_range); 492 | desc.push_back(max_range); 493 | } 494 | desc.push_back(p.sched_downmigrate); 495 | desc.push_back(p.sched_upmigrate); 496 | // DefineBlock>(desc, p, soc); 497 | } 498 | 499 | template <> 500 | UperfBoostWalt::Tunables TranslateBlock(ParamSeq::const_iterator &it_seq, ParamDesc::const_iterator &it_desc, 501 | const Soc *soc) { 502 | UperfBoostWalt::Tunables t; 503 | 504 | int idx = 0; 505 | for (const auto &cluster : soc->clusters_) { 506 | t.min_freq[idx] = QuatFreqParam(*it_seq++, cluster, *it_desc++); 507 | t.max_freq[idx] = QuatFreqParam(*it_seq++, cluster, *it_desc++); 508 | t.max_freq[idx] = std::max(t.min_freq[idx], t.max_freq[idx]); 509 | ++idx; 510 | } 511 | t.sched_down = Quantify(*it_seq++, *it_desc++); 512 | t.sched_up = Quantify(*it_seq++, *it_desc++); 513 | t.sched_up = std::max(t.sched_down, t.sched_up); 514 | // auto iblk = TranslateBlock>(it_seq, it_desc, soc); 515 | // t.little = iblk.t[soc->GetLittleClusterIdx()]; 516 | // t.big = iblk.t[soc->GetBigClusterIdx()]; 517 | t.enabled = true; 518 | 519 | return std::move(t); 520 | } 521 | 522 | template <> 523 | void DefineBlock(ParamDesc &desc, const ParamDescCfg &p, const Soc *soc) { 524 | for (const auto &cluster : soc->clusters_) { 525 | // 最大频率不能限制太多,否则影响突发性能,选择0.66*最大主频和1.2g较高的值 526 | int max_freq_floor = 0.66 * cluster.model_.max_freq; 527 | max_freq_floor = std::min(std::max(1200, max_freq_floor), cluster.model_.max_freq); 528 | auto min_range = ParamDescElement{cluster.model_.min_freq, cluster.model_.max_freq}; 529 | auto max_range = ParamDescElement{max_freq_floor, cluster.model_.max_freq}; 530 | desc.push_back(min_range); 531 | desc.push_back(max_range); 532 | } 533 | desc.push_back(p.down_threshold); 534 | desc.push_back(p.up_threshold); 535 | // DefineBlock>(desc, p, soc); 536 | } 537 | 538 | template <> 539 | UperfBoostPelt::Tunables TranslateBlock(ParamSeq::const_iterator &it_seq, ParamDesc::const_iterator &it_desc, 540 | const Soc *soc) { 541 | UperfBoostPelt::Tunables t; 542 | 543 | int idx = 0; 544 | for (const auto &cluster : soc->clusters_) { 545 | t.min_freq[idx] = QuatFreqParam(*it_seq++, cluster, *it_desc++); 546 | t.max_freq[idx] = QuatFreqParam(*it_seq++, cluster, *it_desc++); 547 | t.max_freq[idx] = std::max(t.min_freq[idx], t.max_freq[idx]); 548 | ++idx; 549 | } 550 | t.sched_down = Quantify(*it_seq++, *it_desc++); 551 | t.sched_up = Quantify(*it_seq++, *it_desc++); 552 | t.sched_up = std::max(t.sched_down, t.sched_up); 553 | // auto iblk = TranslateBlock>(it_seq, it_desc, soc); 554 | // t.little = iblk.t[soc->GetLittleClusterIdx()]; 555 | // t.big = iblk.t[soc->GetBigClusterIdx()]; 556 | t.enabled = true; 557 | 558 | return std::move(t); 559 | } 560 | 561 | template 562 | bool IsSupportBoost(const Soc *soc) { 563 | return false; 564 | } 565 | 566 | template <> 567 | bool IsSupportBoost(const Soc *soc) { 568 | return soc->GetInputBoostFeature(); 569 | } 570 | 571 | template <> 572 | bool IsSupportBoost(const Soc *soc) { 573 | return soc->GetInputBoostFeature(); 574 | } 575 | 576 | template <> 577 | bool IsSupportBoost(const Soc *soc) { 578 | return true; 579 | } 580 | 581 | template <> 582 | bool IsSupportBoost(const Soc *soc) { 583 | return true; 584 | } 585 | 586 | template 587 | typename SimType::Tunables OpengaAdapter::TranslateParamSeq(const ParamSeq &p) const { 588 | typename SimType::Tunables t; 589 | 590 | ParamSeq::const_iterator it_seq = p.begin(); 591 | ParamDesc::const_iterator it_desc = param_desc_.begin(); 592 | // cpufreq调速器参数上下限 593 | t.governor = TranslateBlock>(it_seq, it_desc, soc_); 594 | // sched任务调度器参数上下限 595 | t.sched = TranslateBlock(it_seq, it_desc, soc_); 596 | // 是否启用boost 597 | t.has_boost = IsSupportBoost(soc_); 598 | if (t.has_boost) { 599 | // boost升频参数上下限 600 | t.boost = TranslateBlock(it_seq, it_desc, soc_); 601 | } 602 | return t; 603 | } 604 | 605 | template 606 | void OpengaAdapter::InitParamDesc(const ParamDescCfg &p) { 607 | // cpufreq调速器参数上下限 608 | DefineBlock>(param_desc_, p, soc_); 609 | // sched任务调度器参数上下限 610 | DefineBlock(param_desc_, p, soc_); 611 | // 是否启用boost 612 | if (IsSupportBoost(soc_)) { 613 | // boost升频参数上下限 614 | DefineBlock(param_desc_, p, soc_); 615 | } 616 | param_len_ = param_desc_.size(); 617 | } 618 | 619 | template 620 | typename SimType::Tunables OpengaAdapter::GenerateDefaultTunables(void) const { 621 | typename SimType::Tunables t; 622 | // cpufreq调速器参数上下限 623 | int idx = 0; 624 | for (const auto &cluster : soc_->clusters_) 625 | t.governor.t[idx++] = typename SimType::Governor::Tunables(cluster); 626 | // sched任务调度器参数上下限 627 | t.sched = typename SimType::Sched::Tunables(); 628 | // 是否启用boost 629 | if (IsSupportBoost(soc_)) { 630 | // boost升频参数上下限 631 | t.boost = typename SimType::Boost::Tunables(soc_); 632 | } 633 | return t; 634 | } 635 | 636 | template class OpengaAdapter; 637 | template class OpengaAdapter; 638 | template class OpengaAdapter; 639 | template class OpengaAdapter; 640 | -------------------------------------------------------------------------------- /source/opt/openga_helper.h: -------------------------------------------------------------------------------- 1 | #ifndef __OPENGA_HELPER_H 2 | #define __OPENGA_HELPER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "cpumodel.h" 8 | #include "hmp_pelt.h" 9 | #include "hmp_walt.h" 10 | #include "input_boost.h" 11 | #include "interactive.h" 12 | #include "openga.hpp" 13 | #include "rank.h" 14 | #include "sim.hpp" 15 | #include "sim_types.h" 16 | #include "workload.h" 17 | 18 | using InputBoostWalt = InputBoost; 19 | using InputBoostPelt = InputBoost; 20 | using UperfBoostWalt = UperfBoost; 21 | using UperfBoostPelt = UperfBoost; 22 | 23 | using SimQcomBL = Sim; 24 | using SimBL = Sim; 25 | using SimQcomUp = Sim; 26 | using SimUp = Sim; 27 | 28 | typedef struct _ParamDescElement { 29 | int range_start; 30 | int range_end; 31 | } ParamDescElement; 32 | 33 | typedef struct _ParamDescCfg { 34 | ParamDescElement above_hispeed_delay; 35 | ParamDescElement go_hispeed_load; 36 | ParamDescElement max_freq_hysteresis; 37 | ParamDescElement min_sample_time; 38 | ParamDescElement target_loads; 39 | ParamDescElement sched_downmigrate; 40 | ParamDescElement sched_upmigrate; 41 | ParamDescElement sched_ravg_hist_size; 42 | ParamDescElement sched_window_stats_policy; 43 | ParamDescElement sched_boost; 44 | ParamDescElement timer_rate; 45 | ParamDescElement input_duration; 46 | ParamDescElement load_avg_period_ms; 47 | ParamDescElement down_threshold; 48 | ParamDescElement up_threshold; 49 | ParamDescElement boost; 50 | } ParamDescCfg; 51 | 52 | using ParamSeq = std::vector; 53 | using ParamDesc = std::vector; 54 | 55 | template 56 | class OpengaAdapter { 57 | public: 58 | typedef struct _GaCfg { 59 | int population; 60 | int generation_max; 61 | float crossover_fraction; 62 | float mutation_rate; 63 | float eta; 64 | int thread_num; 65 | uint64_t random_seed; 66 | } GaCfg; 67 | 68 | typedef struct _MiscConst { 69 | double idle_fraction; 70 | double work_fraction; 71 | double idle_lasting_min; 72 | double performance_max; 73 | } MiscConst; 74 | 75 | typedef struct _MiddleCost { 76 | double c1; 77 | double c2; 78 | double c3; 79 | } MiddleCost; 80 | 81 | struct Result { 82 | typename SimType::Tunables tunable; 83 | Rank::Score score; 84 | }; 85 | 86 | using GA_Type = EA::Genetic; 87 | using RandomFunc = std::function; 88 | 89 | OpengaAdapter(Soc *soc, const Workload *workload, const Workload *idleload, const std::string &ga_cfg_file); 90 | std::vector Optimize(void); 91 | 92 | private: 93 | OpengaAdapter(); 94 | std::vector CalcMultiObjectives(const typename GA_Type::thisChromosomeType &X) { 95 | // result.c1 = score.performance; // 卡顿程度,越小越好 96 | // result.c2 = score.battery_life; // 亮屏续航,越大越好 97 | // result.c3 = score.idle_lasting // 灭屏待机,越大越好 98 | return {X.middle_costs.c1, 99 | -(misc_.work_fraction * X.middle_costs.c2 + misc_.idle_fraction * X.middle_costs.c3)}; 100 | } 101 | 102 | ParamSeq Mutate(const ParamSeq &X_base, const RandomFunc &rnd01, double shrink_scale); 103 | ParamSeq Crossover(const ParamSeq &X1, const ParamSeq &X2, const RandomFunc &rnd01); 104 | 105 | typename SimType::Tunables TranslateParamSeq(const ParamSeq &p) const; 106 | typename SimType::Tunables GenerateDefaultTunables(void) const; 107 | void InitParamDesc(const ParamDescCfg &p); 108 | 109 | void MO_report_generation(int generation_number, const EA::GenerationType &last_generation, 110 | const std::vector &pareto_front); 111 | 112 | void InitParamSeq(ParamSeq &p, const RandomFunc &rnd01); 113 | bool EvalParamSeq(const ParamSeq ¶m_seq, MiddleCost &result); 114 | void InitDefaultScore(); 115 | void InitDefaultPowersum(); 116 | void ParseCfgFile(const std::string &ga_cfg_file); 117 | 118 | Soc * soc_; 119 | const Workload *workload_; 120 | const Workload *idleload_; 121 | Rank::Score default_score_; 122 | int param_len_; 123 | ParamDesc param_desc_; 124 | GaCfg ga_cfg_; 125 | MiscConst misc_; 126 | 127 | typename SimType::MiscConst sim_misc_; 128 | Rank::MiscConst rank_misc_; 129 | }; 130 | 131 | #endif 132 | -------------------------------------------------------------------------------- /source/output/dump.h: -------------------------------------------------------------------------------- 1 | #ifndef __DUMP_H 2 | #define __DUMP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "cpumodel.h" 8 | #include "openga_helper.h" 9 | #include "sim.hpp" 10 | 11 | template 12 | class Dumper { 13 | #define PERF_LEVEL_NUM 7 14 | public: 15 | using OpengaResults = std::vector::Result>; 16 | 17 | Dumper() = delete; 18 | Dumper(const Soc &soc, const std::string &output_path) : soc_(soc), output_path_(output_path){}; 19 | void DumpToTXT(const OpengaResults &results) const; 20 | void DumpToCSV(const OpengaResults &results) const; 21 | void DumpToShellScript(const OpengaResults &results); 22 | void DumpToUperfJson(const OpengaResults &results) const; 23 | 24 | private: 25 | std::string SimTunableToStr(const typename SimType::Tunables &t) const; 26 | std::string LevelToStr(const typename SimType::Tunables &t, int level) const; 27 | std::string SysfsObjToStr(void); 28 | 29 | const Soc soc_; 30 | const std::string output_path_; 31 | 32 | int n_param_; 33 | }; 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /source/sim/cpumodel.cpp: -------------------------------------------------------------------------------- 1 | #include "cpumodel.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "json.hpp" 7 | 8 | Cluster::Cluster(Model model) : model_(model) { 9 | busy_pct_ = 0; 10 | SetMinfreq(model.min_freq); 11 | SetMaxfreq(model.max_freq); 12 | SetCurfreq(model.max_freq); 13 | } 14 | 15 | Soc::Soc(const std::string &model_file) { 16 | std::ifstream ifs(model_file); 17 | nlohmann::json j; 18 | ifs >> j; 19 | 20 | // SOC的型号 21 | name_ = j["name"]; 22 | 23 | // 提供的容量大于SOC最大容量xx%的跳过卡顿判断 24 | enough_capacity_pct_ = j["enoughCapacityPct"]; 25 | 26 | // 使用的调度器类型 27 | if (j["sched"] == "walt") 28 | sched_type_ = kWalt; 29 | else if (j["sched"] == "pelt") 30 | sched_type_ = kPelt; 31 | else 32 | sched_type_ = kLegacy; 33 | 34 | // 多核心模式 35 | if (j["intra"] == "asmp") 36 | intra_type_ = kASMP; 37 | else 38 | intra_type_ = kSMP; 39 | 40 | // 是否支持输入升频 41 | input_boost_ = j["inputBoost"]; 42 | 43 | // 频点与功耗 44 | for (const auto &it : j["cluster"]) { 45 | Cluster::Model m; 46 | m.core_num = it["coreNum"]; 47 | m.efficiency = it["efficiency"]; 48 | m.min_freq = it["minFreq"]; 49 | m.max_freq = it["maxFreq"]; 50 | m.opp_model.reserve(it["opp"].size()); 51 | for (uint32_t i = 0; i < it["opp"].size(); ++i) { 52 | m.opp_model.push_back({it["opp"][i], it["corePower"][i], it["clusterPower"][i]}); 53 | } 54 | clusters_.push_back(Cluster(m)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /source/sim/cpumodel.h: -------------------------------------------------------------------------------- 1 | #ifndef __CPU_MODEL_H 2 | #define __CPU_MODEL_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | class Cluster { 10 | public: 11 | typedef struct _Pwr { 12 | int16_t freq; 13 | int16_t core_power; 14 | int16_t cluster_power; 15 | } Pwr; 16 | 17 | typedef struct _ClusterModel { 18 | int min_freq; 19 | int max_freq; 20 | int efficiency; 21 | int core_num; 22 | std::vector opp_model; 23 | } Model; 24 | 25 | Cluster(Model model); 26 | int FindFreqIdx(int freq, int left, int right) const; 27 | int freq_floor_to_idx(int freq) const; 28 | int freq_ceiling_to_idx(int freq) const; 29 | int freq_floor_to_opp(int freq) const; 30 | int freq_ceiling_to_opp(int freq) const; 31 | int CalcPower(const int *load_pcts) const; 32 | int CalcCapacity(void) const; 33 | int GetBusyPct(void) const { return busy_pct_; } 34 | int GetMinfreq(void) const { return min_freq_; } 35 | int GetMaxfreq(void) const { return max_freq_; } 36 | int GetCurfreq(void) const { return cur_freq_; } 37 | int GetOpp(int idx) const { return model_.opp_model[idx].freq; } 38 | void SetBusyPct(int load) { busy_pct_ = load; } 39 | void SetMinfreq(int freq); 40 | void SetMaxfreq(int freq); 41 | void SetCurfreq(int freq); 42 | 43 | const Model model_; 44 | 45 | private: 46 | Cluster(); 47 | 48 | int busy_pct_; 49 | int min_freq_; 50 | int max_freq_; 51 | int cur_freq_; 52 | int min_opp_idx_; 53 | int max_opp_idx_; 54 | int cur_opp_idx_; 55 | }; 56 | 57 | // 在给定下标闭区间内,找到 >=@freq的最低频点对应的opp频点序号 58 | inline int Cluster::FindFreqIdx(int freq, int left, int right) const { 59 | left = (left == -1) ? 0 : left; 60 | right = (right == -1) ? (model_.opp_model.size() - 1) : right; 61 | int i = left; 62 | // 第1-n个频点,到达第n或者当前频点>=要寻找的即可跳出 63 | for (; i < right && GetOpp(i) < freq; ++i) 64 | ; 65 | return i; 66 | } 67 | 68 | // 在最低最高频率范围内,找到 >=@freq的最低频点对应的opp频点序号 69 | inline int Cluster::freq_floor_to_idx(int freq) const { 70 | return FindFreqIdx(freq, min_opp_idx_, max_opp_idx_); 71 | } 72 | 73 | // 在最低最高频率范围内,找到 <=@freq的最大频点对应的opp频点序号 74 | inline int Cluster::freq_ceiling_to_idx(int freq) const { 75 | int i = FindFreqIdx(freq, min_opp_idx_, max_opp_idx_); 76 | return (i > 0 && GetOpp(i) > freq) ? (i - 1) : i; 77 | } 78 | 79 | // 在最低最高频率范围内,找到 >=@freq的最低频点 80 | inline int Cluster::freq_floor_to_opp(int freq) const { 81 | return GetOpp(freq_floor_to_idx(freq)); 82 | } 83 | 84 | // 在最低最高频率范围内,找到 <=@freq的最大频点 85 | inline int Cluster::freq_ceiling_to_opp(int freq) const { 86 | return GetOpp(freq_ceiling_to_idx(freq)); 87 | } 88 | 89 | inline void Cluster::SetMinfreq(int freq) { 90 | min_opp_idx_ = FindFreqIdx(freq, -1, -1); 91 | min_freq_ = GetOpp(min_opp_idx_); 92 | if (cur_freq_ < min_freq_) 93 | SetCurfreq(min_freq_); 94 | } 95 | 96 | inline void Cluster::SetMaxfreq(int freq) { 97 | max_opp_idx_ = FindFreqIdx(freq, -1, -1); 98 | max_freq_ = GetOpp(max_opp_idx_); 99 | if (cur_freq_ > max_freq_) 100 | SetCurfreq(max_freq_); 101 | } 102 | 103 | inline void Cluster::SetCurfreq(int freq) { 104 | cur_opp_idx_ = freq_floor_to_idx(freq); 105 | cur_freq_ = GetOpp(cur_opp_idx_); 106 | } 107 | 108 | // 耗电量 = 功耗(mw) * 占用率(最大100) 109 | inline int Cluster::CalcPower(const int *load_pcts) const { 110 | int pwr = model_.opp_model[cur_opp_idx_].cluster_power * 100; 111 | int core_pwr = model_.opp_model[cur_opp_idx_].core_power; 112 | for (int i = 0; i < model_.core_num; ++i) { 113 | pwr += core_pwr * load_pcts[i]; 114 | } 115 | return pwr; 116 | } 117 | 118 | inline int Cluster::CalcCapacity() const { 119 | return (cur_freq_ * model_.efficiency * 100); 120 | } 121 | 122 | class Soc { 123 | public: 124 | // 多核心模式 125 | typedef enum _IntraType { kSMP = 0, kASMP } IntraType; 126 | // 使用的调度器类型 127 | typedef enum _SchedType { kLegacy = 0, kWalt, kPelt } SchedType; 128 | 129 | Soc(const std::string &model_file); 130 | ~Soc(){}; 131 | 132 | IntraType GetIntraType(void) const { return intra_type_; } 133 | SchedType GetSchedType(void) const { return sched_type_; } 134 | bool GetInputBoostFeature(void) const { return input_boost_; } 135 | 136 | int GetLittleClusterIdx(void) const { return 0; } 137 | int GetBigClusterIdx(void) const { return clusters_.size() - 1; } 138 | 139 | int GetEnoughCapacity(void) const { 140 | return (clusters_.back().model_.max_freq * clusters_.back().model_.efficiency * enough_capacity_pct_); 141 | } 142 | 143 | int GetMaxCapacity(void) const { 144 | return (clusters_.back().model_.max_freq * clusters_.back().model_.efficiency * 98); 145 | } 146 | 147 | std::string name_; 148 | std::vector clusters_; 149 | 150 | private: 151 | Soc(); 152 | 153 | IntraType intra_type_; 154 | SchedType sched_type_; 155 | bool input_boost_; 156 | int enough_capacity_pct_; // 提供的容量大于SOC最大容量xx%的跳过卡顿判断 157 | }; 158 | 159 | #endif 160 | -------------------------------------------------------------------------------- /source/sim/hmp.h: -------------------------------------------------------------------------------- 1 | #ifndef __HMP_H 2 | #define __HMP_H 3 | 4 | #include 5 | 6 | #include "cpumodel.h" 7 | #include "interactive.h" 8 | 9 | class Hmp { 10 | public: 11 | struct HmpTunables {}; 12 | 13 | struct HmpCfg { 14 | Cluster * little; 15 | Cluster * big; 16 | Interactive *governor_little; 17 | Interactive *governor_big; 18 | }; 19 | 20 | Hmp(){}; 21 | Hmp(HmpCfg cfg) 22 | : little_(cfg.little), 23 | big_(cfg.big), 24 | active_(big_), 25 | idle_(little_), 26 | governor_little_(cfg.governor_little), 27 | governor_big_(cfg.governor_big), 28 | up_demand_thd_(0), 29 | down_demand_thd_(0) { 30 | cluster_num_ = (big_ == little_) ? 1 : 2; 31 | } 32 | 33 | int SchedulerTick(int max_load, const int *loads, int n_load, int now) { return 0; }; 34 | int CalcPower(const int *loads) const; 35 | int CalcPowerForIdle(const int *loads) const; 36 | 37 | protected: 38 | #define NLoadsMax 4 39 | int LoadToBusyPct(const Cluster *c, uint64_t load) const; 40 | 41 | Cluster * little_; 42 | Cluster * big_; 43 | Cluster * active_; 44 | Cluster * idle_; 45 | Interactive *governor_little_; 46 | Interactive *governor_big_; 47 | int cluster_num_; 48 | uint64_t up_demand_thd_; 49 | uint64_t down_demand_thd_; 50 | }; 51 | 52 | inline int Hmp::LoadToBusyPct(const Cluster *c, uint64_t load) const { 53 | return (load / (c->GetCurfreq() * c->model_.efficiency)); 54 | } 55 | 56 | // 外层保证已执行adaptload,负载百分比不超过100% 57 | // loads: freq * busy_pct * efficiency 58 | inline int Hmp::CalcPower(const int *loads) const { 59 | const int idle_load_pcts[] = {1, 0, 0, 0}; 60 | int load_pcts[NLoadsMax]; 61 | for (int i = 0; i < NLoadsMax; ++i) { 62 | load_pcts[i] = loads[i] / (active_->model_.efficiency * active_->GetCurfreq()); 63 | } 64 | 65 | int pwr = 0; 66 | pwr += active_->CalcPower(load_pcts); 67 | pwr += idle_->CalcPower(idle_load_pcts); 68 | return pwr; 69 | } 70 | 71 | // 如果负载没有被移动到大核,则认为大核没有闲置耗电,减少待机时大核上线概率 72 | inline int Hmp::CalcPowerForIdle(const int *loads) const { 73 | const int idle_load_pcts[] = {100, 0, 0, 0}; 74 | int pwr = 0; 75 | if (active_ == little_) { 76 | pwr += little_->CalcPower(idle_load_pcts); 77 | } else { 78 | pwr += little_->CalcPower(idle_load_pcts); 79 | pwr += big_->CalcPower(idle_load_pcts); 80 | } 81 | return pwr; 82 | } 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /source/sim/hmp_pelt.cpp: -------------------------------------------------------------------------------- 1 | #include "hmp_pelt.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | /* Precomputed fixed inverse multiplies for multiplication by y^n */ 11 | // runnable_avg_yN_inv[i] = ((1UL << 32) - 1) * pow(0.97857206, i),i>=0 && i<32 12 | static const uint32_t runnable_avg_yN_inv[] = { 13 | 0xffffffff, 0xfa83b2da, 0xf5257d14, 0xefe4b99a, 0xeac0c6e6, 0xe5b906e6, 0xe0ccdeeb, 0xdbfbb796, 14 | 0xd744fcc9, 0xd2a81d91, 0xce248c14, 0xc9b9bd85, 0xc5672a10, 0xc12c4cc9, 0xbd08a39e, 0xb8fbaf46, 15 | 0xb504f333, 0xb123f581, 0xad583ee9, 0xa9a15ab4, 0xa5fed6a9, 0xa2704302, 0x9ef5325f, 0x9b8d39b9, 16 | 0x9837f050, 0x94f4efa8, 0x91c3d373, 0x8ea4398a, 0x8b95c1e3, 0x88980e80, 0x85aac367, 0x82cd8698, 17 | }; 18 | #define LOAD_AVG_PERIOD 32 19 | #define LOAD_AVG_MAX 47742 /* maximum possible load avg */ 20 | #define LOAD_AVG_MAX_N 345 /* number of full periods to produce LOAD_AVG_MAX */ 21 | 22 | // a * mul >> shift 23 | static inline uint64_t mul_u64_u32_shr(uint64_t a, uint32_t mul, unsigned int shift) { 24 | uint32_t ah, al; 25 | uint64_t ret; 26 | 27 | al = a; 28 | ah = a >> 32; 29 | 30 | ret = ((uint64_t)al * mul) >> shift; 31 | if (ah) 32 | ret += ((uint64_t)ah * mul) << (32 - shift); 33 | 34 | return ret; 35 | } 36 | 37 | /* 38 | * Approximate: 39 | * val * y^n, where y^32 ~= 0.5 (~1 scheduling period) 40 | */ 41 | static inline uint64_t decay_load(uint64_t val, uint64_t n) { 42 | // unsigned int local_n; 43 | 44 | // if (!n) 45 | // return val; 46 | // else if (unlikely(n > LOAD_AVG_PERIOD * 63)) 47 | // return 0; 48 | 49 | // /* after bounds checking we can collapse to 32-bit */ 50 | // local_n = n; 51 | 52 | // /* 53 | // * As y^PERIOD = 1/2, we can combine 54 | // * y^n = 1/2^(n/PERIOD) * y^(n%PERIOD) 55 | // * With a look-up table which covers y^n (n= LOAD_AVG_PERIOD)) { 60 | // val >>= local_n / LOAD_AVG_PERIOD; 61 | // local_n %= LOAD_AVG_PERIOD; 62 | // } 63 | // /*正好符合:load = (load >> (n/period)) * y^(n%period)计算方式*/ 64 | // val = mul_u64_u32_shr(val, runnable_avg_yN_inv[local_n], 32); 65 | return val; 66 | } 67 | 68 | uint32_t CalcDecayRatio(int ms, int n) { 69 | // 在LOAD_AVG_PERIOD毫秒时的负载,在当前计算衰减一半 70 | // y为1毫秒前负载的衰减,n为毫秒数,y ^ n = 0.5 71 | double y = pow(0.5, 1.0 / n); 72 | return (UINT32_MAX * pow(y, ms)); 73 | } 74 | 75 | // 根据decay_ratio(0.97 * UINTMAX)计算LoadAvgMax 76 | // CalcDecayRatio(1, 32) -> 47742,迭代348次 77 | // CalcDecayRatio(10, 32) -> 5253,迭代36次 78 | uint32_t CalcLoadAvgMax(uint32_t decay_ratio) { 79 | uint32_t max = 0; 80 | uint32_t last = UINT32_MAX; 81 | while (max != last) { 82 | last = max; 83 | max = 1024 + mul_u64_u32_shr(max, decay_ratio, 32); 84 | } 85 | return max; 86 | } 87 | 88 | PeltHmp::Tunables::Tunables() { 89 | down_threshold = 214; 90 | up_threshold = 524; 91 | load_avg_period_ms = 128; 92 | boost = 0; 93 | timer_rate = 2; 94 | } 95 | 96 | #define TICK_MS 10 97 | PeltHmp::PeltHmp(Cfg cfg) 98 | : Hmp(cfg), demand_(0), entry_cnt_(0), max_load_sum_(0), decay_ratio_(0), load_avg_max_(0), governor_cnt_(0) { 99 | SetTunables(cfg.tunables); 100 | InitDecay(TICK_MS, tunables_.load_avg_period_ms); 101 | } 102 | 103 | void PeltHmp::SetTunables(const Tunables &t) { 104 | tunables_ = t; 105 | up_demand_thd_ = tunables_.up_threshold; 106 | down_demand_thd_ = tunables_.down_threshold; 107 | } 108 | 109 | void PeltHmp::InitDecay(int ms, int n) { 110 | decay_ratio_ = CalcDecayRatio(TICK_MS, tunables_.load_avg_period_ms); 111 | load_avg_max_ = CalcLoadAvgMax(decay_ratio_); 112 | } 113 | 114 | #define THRESHOLD_SCALE 1024 115 | // 用于大小核迁移的使用率计算,以最大可达到的使用率为1024 116 | // 注意这个使用率不考虑当前集群的频率和IPC,仅与CPU忙时间有关 117 | // 同样的负载,在容量较高的核心上使用率会低一些,在容量较低的核心上使用率会高一些 118 | uint64_t PeltHmp::UpdateBusyTime(int max_load) { 119 | // 转换到负载百分比,映射到0~1024 120 | uint64_t now = LoadToBusyPct(active_, max_load) * THRESHOLD_SCALE / 100; 121 | // 衰减之前的负载,加上新的,如果是持续稳定负载类似于等比数列求和 122 | demand_ = now + mul_u64_u32_shr(demand_, decay_ratio_, 32); 123 | // 以最大可达到的使用率为1024 124 | return demand_ * THRESHOLD_SCALE / load_avg_max_; 125 | } 126 | 127 | // demand : freq * busy_pct * efficiency 128 | // load: freq * busy_pct * efficiency 129 | // load 最大值 2500 * 2048 * 100,sum最大值 3000 * 2048 * 400,可能大于UINT32_MAX 130 | int PeltHmp::SchedulerTick(int max_load, const int *loads, int n_load, int now) { 131 | // 仅用于负载迁移判断,调频器仍然使用定期负载采样 132 | // 注意这个使用率不考虑当前集群的频率和IPC,仅与CPU忙时间有关 133 | uint64_t busy = UpdateBusyTime(max_load); 134 | if (busy > up_demand_thd_) { 135 | active_ = big_; 136 | idle_ = little_; 137 | } else if (busy < down_demand_thd_) { 138 | active_ = little_; 139 | idle_ = big_; 140 | } else { 141 | ; 142 | } 143 | 144 | ++entry_cnt_; 145 | max_load_sum_ += max_load; 146 | 147 | if (entry_cnt_ == tunables_.timer_rate) { 148 | int max_load_avg = max_load_sum_ / tunables_.timer_rate; 149 | entry_cnt_ = 0; 150 | max_load_sum_ = 0; 151 | 152 | // 调频器仍然使用定期负载采样 153 | idle_->SetBusyPct(0); 154 | active_->SetBusyPct(LoadToBusyPct(active_, max_load_avg)); 155 | 156 | little_->SetCurfreq(governor_little_->InteractiveTimer(little_->GetBusyPct(), governor_cnt_)); 157 | if (cluster_num_ > 1) 158 | big_->SetCurfreq(governor_big_->InteractiveTimer(big_->GetBusyPct(), governor_cnt_)); 159 | 160 | ++governor_cnt_; 161 | } 162 | 163 | return active_->CalcCapacity(); 164 | } 165 | -------------------------------------------------------------------------------- /source/sim/hmp_pelt.h: -------------------------------------------------------------------------------- 1 | #ifndef __HMP_PELT_H 2 | #define __HMP_PELT_H 3 | 4 | #include "hmp.h" 5 | 6 | class PeltHmp : public Hmp { 7 | public: 8 | struct Tunables : public HmpTunables { 9 | int load_avg_period_ms; 10 | int down_threshold; 11 | int up_threshold; 12 | int boost; 13 | int timer_rate; 14 | Tunables(); 15 | }; 16 | 17 | struct Cfg : public HmpCfg { 18 | Tunables tunables; 19 | }; 20 | 21 | PeltHmp(){}; 22 | PeltHmp(Cfg cfg); 23 | int SchedulerTick(int max_load, const int *loads, int n_load, int now); 24 | 25 | Tunables GetTunables(void) { return tunables_; } 26 | void SetTunables(const Tunables &t); 27 | 28 | private: 29 | uint64_t UpdateBusyTime(int max_load); 30 | void InitDecay(int ms, int n); 31 | 32 | Tunables tunables_; 33 | uint64_t demand_; 34 | int entry_cnt_; 35 | uint64_t max_load_sum_; 36 | uint32_t decay_ratio_; 37 | uint32_t load_avg_max_; 38 | int governor_cnt_; 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /source/sim/hmp_walt.cpp: -------------------------------------------------------------------------------- 1 | #include "hmp_walt.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | WaltHmp::Tunables::Tunables() { 10 | sched_downmigrate = 85; 11 | sched_upmigrate = 95; 12 | sched_ravg_hist_size = 5; 13 | sched_window_stats_policy = WaltHmp::WINDOW_STATS_MAX_RECENT_AVG; 14 | sched_boost = 0; 15 | timer_rate = 2; 16 | } 17 | 18 | WaltHmp::WaltHmp(Cfg cfg) 19 | : Hmp(cfg), tunables_(cfg.tunables), demand_(0), entry_cnt_(0), max_load_sum_(0), governor_cnt_(0) { 20 | SetTunables(cfg.tunables); 21 | memset(sum_history_, 0, sizeof(sum_history_)); 22 | memset(loads_sum_, 0, sizeof(loads_sum_)); 23 | } 24 | 25 | void WaltHmp::SetTunables(const Tunables &t) { 26 | tunables_ = t; 27 | // Hence this threshold is auto-adjusted by a factor 28 | // equal to max_possible_frequency/current_frequency of a lower capacity CPU 29 | up_demand_thd_ = little_->model_.max_freq * little_->model_.efficiency * tunables_.sched_upmigrate; 30 | down_demand_thd_ = little_->model_.max_freq * little_->model_.efficiency * tunables_.sched_downmigrate; 31 | } 32 | 33 | // 更新负载滑动窗口,返回预计的负载需求,@in_demand为freq*busy_pct*efficiency 34 | void WaltHmp::update_history(int in_demand) { 35 | int * hist = sum_history_; 36 | uint64_t sum = 0; 37 | constexpr int samples = 1; 38 | const int runtime = in_demand; 39 | int max = 0; 40 | int ridx, widx; 41 | int avg, demand; 42 | 43 | /* Push new 'runtime' value onto stack */ 44 | widx = tunables_.sched_ravg_hist_size - 1; 45 | ridx = widx - samples; 46 | for (; ridx >= 0; --widx, --ridx) { 47 | hist[widx] = hist[ridx]; 48 | sum += hist[widx]; 49 | if (hist[widx] > max) 50 | max = hist[widx]; 51 | } 52 | 53 | for (widx = 0; widx < samples && widx < tunables_.sched_ravg_hist_size; widx++) { 54 | hist[widx] = runtime; 55 | sum += hist[widx]; 56 | if (hist[widx] > max) 57 | max = hist[widx]; 58 | } 59 | 60 | if (tunables_.sched_window_stats_policy == WINDOW_STATS_RECENT) { 61 | demand = runtime; 62 | } else if (tunables_.sched_window_stats_policy == WINDOW_STATS_MAX) { 63 | demand = max; 64 | } else { 65 | avg = sum / tunables_.sched_ravg_hist_size; 66 | if (tunables_.sched_window_stats_policy == WINDOW_STATS_AVG) 67 | demand = avg; 68 | else 69 | demand = std::max(avg, runtime); 70 | } 71 | 72 | demand_ = demand; 73 | return; 74 | } 75 | 76 | // demand : freq * busy_pct * efficiency,walt输出 77 | // load: freq * busy_pct * efficiency 78 | // load 最大值 2500 * 2048 * 100,sum最大值 3000 * 2048 * 400,可能大于UINT32_MAX 79 | int WaltHmp::SchedulerTick(int max_load, const int *loads, int n_load, int now) { 80 | ++entry_cnt_; 81 | max_load_sum_ += max_load; 82 | for (int i = 0; i < n_load; ++i) { 83 | loads_sum_[i] += loads[i]; 84 | } 85 | 86 | if (entry_cnt_ == tunables_.timer_rate) { 87 | int max_load_avg = max_load_sum_ / tunables_.timer_rate; 88 | 89 | entry_cnt_ = 0; 90 | max_load_sum_ = 0; 91 | memset(loads_sum_, 0, sizeof(loads_sum_)); 92 | 93 | update_history(max_load_avg); 94 | 95 | if (demand_ > up_demand_thd_) { 96 | active_ = big_; 97 | idle_ = little_; 98 | } else if (demand_ < down_demand_thd_) { 99 | active_ = little_; 100 | idle_ = big_; 101 | } else { 102 | ; 103 | } 104 | 105 | if (tunables_.sched_boost) { 106 | active_ = big_; 107 | idle_ = little_; 108 | } 109 | 110 | // 调频器使用定期负载采样 111 | idle_->SetBusyPct(0); 112 | active_->SetBusyPct(LoadToBusyPct(active_, max_load_avg)); 113 | 114 | little_->SetCurfreq(governor_little_->InteractiveTimer(little_->GetBusyPct(), governor_cnt_)); 115 | if (cluster_num_ > 1) 116 | big_->SetCurfreq(governor_big_->InteractiveTimer(big_->GetBusyPct(), governor_cnt_)); 117 | 118 | ++governor_cnt_; 119 | } 120 | 121 | return active_->CalcCapacity(); 122 | } 123 | -------------------------------------------------------------------------------- /source/sim/hmp_walt.h: -------------------------------------------------------------------------------- 1 | #ifndef __HMP_WALT_H 2 | #define __HMP_WALT_H 3 | 4 | #include "hmp.h" 5 | 6 | class WaltHmp : public Hmp { 7 | public: 8 | enum { WINDOW_STATS_RECENT = 0, WINDOW_STATS_MAX, WINDOW_STATS_MAX_RECENT_AVG, WINDOW_STATS_AVG }; 9 | 10 | struct Tunables : public HmpTunables { 11 | int timer_rate; 12 | int sched_upmigrate; 13 | int sched_downmigrate; 14 | int sched_ravg_hist_size; 15 | int sched_window_stats_policy; 16 | int sched_boost; 17 | Tunables(); 18 | }; 19 | 20 | struct Cfg : public HmpCfg { 21 | Tunables tunables; 22 | }; 23 | 24 | WaltHmp(){}; 25 | WaltHmp(Cfg cfg); 26 | int SchedulerTick(int max_load, const int *loads, int n_load, int now); 27 | 28 | Tunables GetTunables(void) { return tunables_; } 29 | void SetTunables(const Tunables &t); 30 | 31 | private: 32 | #define RavgHistSizeMax 5 33 | 34 | void update_history(int in_demand); 35 | 36 | Tunables tunables_; 37 | uint64_t demand_; 38 | int sum_history_[RavgHistSizeMax]; 39 | int entry_cnt_; 40 | uint64_t max_load_sum_; 41 | uint64_t loads_sum_[NLoadsMax]; 42 | int governor_cnt_; 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /source/sim/input_boost.cpp: -------------------------------------------------------------------------------- 1 | #include "input_boost.h" 2 | 3 | #include "hmp_pelt.h" 4 | #include "hmp_walt.h" 5 | 6 | template 7 | InputBoost::Tunables::Tunables(const Soc *soc) { 8 | int idx = 0; 9 | for (const auto &cluster : soc->clusters_) { 10 | boost_freq[idx++] = cluster.freq_floor_to_opp(cluster.model_.max_freq * 0.6); 11 | } 12 | // 默认不拉大核的最低频率 13 | if (soc->clusters_.size() > 1) 14 | boost_freq[1] = soc->clusters_[1].model_.min_freq; 15 | duration_quantum = 100; 16 | } 17 | 18 | template 19 | void InputBoost::DoBoost() { 20 | auto &cls = this->env_.soc->clusters_; 21 | int nr = cls.size(); 22 | for (int i = 0; i < nr; ++i) 23 | cls[i].SetMinfreq(tunables_.boost_freq[i]); 24 | } 25 | 26 | template 27 | void InputBoost::DoResume() { 28 | auto &cls = this->env_.soc->clusters_; 29 | int nr = cls.size(); 30 | for (int i = 0; i < nr; ++i) 31 | cls[i].SetMinfreq(cls[i].model_.min_freq); 32 | } 33 | 34 | template 35 | void InputBoost::Tick(bool has_input, bool has_render, int cur_quantum) { 36 | if (tunables_.duration_quantum && has_input) { 37 | this->input_happened_quantum_ = cur_quantum; 38 | DoBoost(); 39 | this->is_in_boost_ = true; 40 | return; 41 | } 42 | if (this->is_in_boost_ && cur_quantum - this->input_happened_quantum_ > tunables_.duration_quantum) { 43 | DoResume(); 44 | this->is_in_boost_ = false; 45 | } 46 | }; 47 | 48 | template <> 49 | UperfBoost::Tunables::Tunables(const Soc *soc) { 50 | int cluster_num = soc->clusters_.size(); 51 | auto sched_tunables = WaltHmp::Tunables(); 52 | for (int i = 0; i < cluster_num; ++i) { 53 | const auto &cl = soc->clusters_[i]; 54 | min_freq[i] = cl.model_.min_freq; 55 | max_freq[i] = cl.model_.max_freq; 56 | } 57 | sched_up = sched_tunables.sched_upmigrate; 58 | sched_down = sched_tunables.sched_downmigrate; 59 | little = Interactive::Tunables(soc->clusters_[soc->GetLittleClusterIdx()]); 60 | big = Interactive::Tunables(soc->clusters_[soc->GetBigClusterIdx()]); 61 | enabled = true; 62 | } 63 | 64 | template <> 65 | UperfBoost::Tunables::Tunables(const Soc *soc) { 66 | int cluster_num = soc->clusters_.size(); 67 | auto sched_tunables = PeltHmp::Tunables(); 68 | for (int i = 0; i < cluster_num; ++i) { 69 | const auto &cl = soc->clusters_[i]; 70 | min_freq[i] = cl.model_.min_freq; 71 | max_freq[i] = cl.model_.max_freq; 72 | } 73 | sched_up = sched_tunables.up_threshold; 74 | sched_down = sched_tunables.down_threshold; 75 | little = Interactive::Tunables(soc->clusters_[soc->GetLittleClusterIdx()]); 76 | big = Interactive::Tunables(soc->clusters_[soc->GetBigClusterIdx()]); 77 | enabled = true; 78 | } 79 | 80 | template 81 | void UperfBoost::DoBoost() { 82 | if (is_original_inited_ == false) { 83 | is_original_inited_ = true; 84 | Backup(); 85 | } 86 | Apply(tunables_); 87 | } 88 | 89 | template 90 | void UperfBoost::DoResume() { 91 | Apply(original_); 92 | } 93 | 94 | template 95 | void UperfBoost::Tick(bool has_input, bool has_render, int cur_quantum) { 96 | if (tunables_.enabled == false) 97 | return; 98 | 99 | if (has_input) { 100 | this->input_happened_quantum_ = cur_quantum; 101 | } 102 | if (has_render) { 103 | this->render_stop_quantum_ = cur_quantum; 104 | } 105 | 106 | if (this->is_in_boost_ == false) { 107 | if (has_input) { 108 | this->render_stop_quantum_ = cur_quantum; 109 | DoBoost(); 110 | this->is_in_boost_ = true; 111 | } 112 | } else { 113 | // uperf在渲染结束后至多300ms,或者触摸停止后3000ms,停止hint 114 | bool is_touch_timeout = cur_quantum - this->input_happened_quantum_ > 300; 115 | bool is_render_stop = cur_quantum - this->render_stop_quantum_ > 30; 116 | if (is_touch_timeout || is_render_stop) { 117 | DoResume(); 118 | this->is_in_boost_ = false; 119 | } 120 | } 121 | }; 122 | 123 | template <> 124 | void UperfBoost::Apply(const typename UperfBoost::Tunables &t) { 125 | auto soc = this->env_.soc; 126 | // auto little = this->env_.little; 127 | // auto big = this->env_.big; 128 | auto sched = this->env_.sched; 129 | 130 | int cluster_num = soc->clusters_.size(); 131 | auto sched_tunables = sched->GetTunables(); 132 | for (int i = 0; i < cluster_num; ++i) { 133 | soc->clusters_[i].SetMinfreq(t.min_freq[i]); 134 | soc->clusters_[i].SetMaxfreq(t.max_freq[i]); 135 | } 136 | sched_tunables.sched_upmigrate = t.sched_up; 137 | sched_tunables.sched_downmigrate = t.sched_down; 138 | sched->SetTunables(sched_tunables); 139 | // little->SetTunables(t.little); 140 | // big->SetTunables(t.big); 141 | } 142 | 143 | template <> 144 | void UperfBoost::Apply(const typename UperfBoost::Tunables &t) { 145 | auto soc = this->env_.soc; 146 | // auto little = this->env_.little; 147 | // auto big = this->env_.big; 148 | auto sched = this->env_.sched; 149 | 150 | int cluster_num = soc->clusters_.size(); 151 | auto sched_tunables = sched->GetTunables(); 152 | for (int i = 0; i < cluster_num; ++i) { 153 | soc->clusters_[i].SetMinfreq(t.min_freq[i]); 154 | soc->clusters_[i].SetMaxfreq(t.max_freq[i]); 155 | } 156 | sched_tunables.up_threshold = t.sched_up; 157 | sched_tunables.down_threshold = t.sched_down; 158 | sched->SetTunables(sched_tunables); 159 | // little->SetTunables(t.little); 160 | // big->SetTunables(t.big); 161 | } 162 | 163 | template <> 164 | void UperfBoost::Backup() { 165 | const auto soc = this->env_.soc; 166 | const auto little = this->env_.little; 167 | const auto big = this->env_.big; 168 | const auto sched = this->env_.sched; 169 | 170 | int cluster_num = soc->clusters_.size(); 171 | auto sched_tunables = sched->GetTunables(); 172 | for (int i = 0; i < cluster_num; ++i) { 173 | original_.min_freq[i] = soc->clusters_[i].model_.min_freq; 174 | original_.max_freq[i] = soc->clusters_[i].model_.max_freq; 175 | } 176 | original_.sched_up = sched_tunables.sched_upmigrate; 177 | original_.sched_down = sched_tunables.sched_downmigrate; 178 | original_.little = little->GetTunables(); 179 | original_.big = big->GetTunables(); 180 | } 181 | 182 | template <> 183 | void UperfBoost::Backup() { 184 | const auto soc = this->env_.soc; 185 | const auto little = this->env_.little; 186 | const auto big = this->env_.big; 187 | const auto sched = this->env_.sched; 188 | 189 | int cluster_num = soc->clusters_.size(); 190 | auto sched_tunables = sched->GetTunables(); 191 | for (int i = 0; i < cluster_num; ++i) { 192 | original_.min_freq[i] = soc->clusters_[i].model_.min_freq; 193 | original_.max_freq[i] = soc->clusters_[i].model_.max_freq; 194 | } 195 | original_.sched_up = sched_tunables.up_threshold; 196 | original_.sched_down = sched_tunables.down_threshold; 197 | original_.little = little->GetTunables(); 198 | original_.big = big->GetTunables(); 199 | } 200 | 201 | template class InputBoost; 202 | template class InputBoost; 203 | template class UperfBoost; 204 | template class UperfBoost; 205 | -------------------------------------------------------------------------------- /source/sim/input_boost.h: -------------------------------------------------------------------------------- 1 | #ifndef __INPUT_BOOST_H 2 | #define __INPUT_BOOST_H 3 | 4 | #include "cpumodel.h" 5 | 6 | template 7 | class Boost { 8 | public: 9 | struct SysEnv { 10 | Soc * soc; 11 | GovernorT *little; 12 | GovernorT *big; 13 | SchedT * sched; 14 | }; 15 | 16 | Boost() : env_(), is_in_boost_(false) {} 17 | Boost(const SysEnv &env) : env_(env), is_in_boost_(false) {} 18 | void Tick(bool has_input, bool has_render, int cur_quantum) {} 19 | 20 | protected: 21 | void DoBoost(void) {} 22 | void DoResume(void) {} 23 | 24 | SysEnv env_; 25 | bool is_in_boost_; 26 | }; 27 | 28 | template 29 | class InputBoost : public Boost { 30 | public: 31 | struct Tunables { 32 | int boost_freq[2]; 33 | int duration_quantum; 34 | Tunables() : boost_freq{0, 0}, duration_quantum(0) {} 35 | Tunables(const Soc *soc); 36 | }; 37 | 38 | InputBoost() : Boost(), tunables_(), input_happened_quantum_(0) {} 39 | InputBoost(const Tunables &tunables, const typename Boost::SysEnv &env) 40 | : Boost(env), tunables_(tunables), input_happened_quantum_(0) {} 41 | void Tick(bool has_input, bool has_render, int cur_quantum); 42 | 43 | private: 44 | void DoBoost(void); 45 | void DoResume(void); 46 | 47 | Tunables tunables_; 48 | int input_happened_quantum_; 49 | }; 50 | 51 | template 52 | class UperfBoost : public Boost { 53 | public: 54 | struct Tunables { 55 | int min_freq[2]; 56 | int max_freq[2]; 57 | int sched_up; 58 | int sched_down; 59 | typename GovernorT::Tunables little; 60 | typename GovernorT::Tunables big; 61 | bool enabled; 62 | Tunables() : min_freq{0, 0}, max_freq{0, 0}, sched_up(0), sched_down(0), enabled(false) {} 63 | Tunables(const Soc *soc); 64 | }; 65 | 66 | UperfBoost() 67 | : Boost(), 68 | tunables_(), 69 | original_(), 70 | is_original_inited_(false), 71 | render_stop_quantum_(0), 72 | input_happened_quantum_(0) {} 73 | UperfBoost(const Tunables &tunables, const typename Boost::SysEnv &env) 74 | : Boost(env), 75 | tunables_(tunables), 76 | original_(), 77 | is_original_inited_(false), 78 | render_stop_quantum_(0), 79 | input_happened_quantum_(0) {} 80 | void Tick(bool has_input, bool has_render, int cur_quantum); 81 | 82 | private: 83 | void DoBoost(void); 84 | void DoResume(void); 85 | void Apply(const Tunables &t); 86 | void Backup(void); 87 | 88 | Tunables tunables_; 89 | Tunables original_; 90 | 91 | bool is_original_inited_; 92 | int render_stop_quantum_; 93 | int input_happened_quantum_; 94 | }; 95 | 96 | #endif -------------------------------------------------------------------------------- /source/sim/interactive.cpp: -------------------------------------------------------------------------------- 1 | #include "interactive.h" 2 | 3 | #include 4 | extern "C" { 5 | #include 6 | #include 7 | } 8 | 9 | Interactive::Tunables::_InteractiveTunables(const Cluster &cm) { 10 | hispeed_freq = cm.freq_floor_to_opp(cm.model_.max_freq * 0.6); 11 | go_hispeed_load = 90; 12 | min_sample_time = 1; 13 | max_freq_hysteresis = 2; 14 | 15 | int n_opp = cm.model_.opp_model.size(); 16 | int n_above = std::min(ABOVE_DELAY_MAX_LEN, n_opp); 17 | int n_targetloads = std::min(TARGET_LOAD_MAX_LEN, n_opp); 18 | 19 | for (int i = 0; i < n_above; ++i) { 20 | above_hispeed_delay[i] = 1; 21 | } 22 | for (int i = 0; i < n_targetloads; ++i) { 23 | target_loads[i] = 90; 24 | } 25 | } 26 | 27 | int Interactive::choose_freq(int freq, int load) const { 28 | const int loadadjfreq = freq * load; 29 | int prevfreq, freqmin, freqmax, tl; 30 | 31 | freqmin = 0; 32 | freqmax = INT_MAX; 33 | 34 | do { 35 | prevfreq = freq; 36 | tl = freq_to_targetload(freq); 37 | freq = cluster_->freq_floor_to_opp(loadadjfreq / tl); 38 | 39 | if (freq > prevfreq) { 40 | /* The previous frequency is too low. */ 41 | freqmin = prevfreq; 42 | if (freq >= freqmax) { 43 | freq = cluster_->freq_ceiling_to_opp(freqmax - 1); 44 | if (freq == freqmin) { 45 | freq = freqmax; 46 | break; 47 | } 48 | } 49 | } else if (freq < prevfreq) { 50 | /* The previous frequency is high enough. */ 51 | freqmax = prevfreq; 52 | if (freq <= freqmin) { 53 | freq = cluster_->freq_floor_to_opp(freqmin + 1); 54 | if (freq == freqmax) 55 | break; 56 | } 57 | } 58 | } while (freq != prevfreq); 59 | 60 | return freq; 61 | } 62 | 63 | int Interactive::InteractiveTimer(int load, int now) { 64 | bool skip_hispeed_logic = false; 65 | bool skip_min_sample_time = false; 66 | bool jump_to_max_no_ts = false; 67 | bool jump_to_max = false; 68 | constexpr bool boosted = 0; 69 | // bool boosted = now < boostpulse_endtime; // touch->store_boostpulse->boostpulse_endtime 70 | // 通路不再使用,改用input_boost 71 | int new_freq = choose_freq(target_freq, load); 72 | // printf("choosefreq:%d\n", new_freq); 73 | 74 | if (now - max_freq_hyst_start_time < tunables_.max_freq_hysteresis && load >= tunables_.go_hispeed_load) { 75 | skip_hispeed_logic = true; 76 | skip_min_sample_time = true; 77 | if (!jump_to_max) 78 | jump_to_max_no_ts = true; 79 | } 80 | 81 | if (jump_to_max_no_ts || jump_to_max) { 82 | new_freq = cluster_->GetMaxfreq(); 83 | } else if (!skip_hispeed_logic) { 84 | if (load >= tunables_.go_hispeed_load || boosted) { 85 | if (target_freq < tunables_.hispeed_freq) 86 | new_freq = tunables_.hispeed_freq; 87 | else 88 | new_freq = std::max(new_freq, tunables_.hispeed_freq); 89 | } 90 | } 91 | 92 | if (now - max_freq_hyst_start_time < tunables_.max_freq_hysteresis) { 93 | new_freq = std::max(tunables_.hispeed_freq, new_freq); 94 | } 95 | if (!skip_hispeed_logic && target_freq >= tunables_.hispeed_freq && new_freq > target_freq && 96 | now - hispeed_validate_time < freq_to_above_hispeed_delay(target_freq)) { 97 | return target_freq; 98 | } 99 | 100 | hispeed_validate_time = now; 101 | 102 | new_freq = cluster_->freq_floor_to_opp(new_freq); 103 | 104 | /* 105 | * Do not scale below floor_freq unless we have been at or above the 106 | * floor frequency for the minimum sample time since last validated. 107 | */ 108 | if (!skip_min_sample_time && new_freq < floor_freq) { 109 | if (now - floor_validate_time < tunables_.min_sample_time) { 110 | return target_freq; 111 | } 112 | } 113 | 114 | /* 115 | * Update the timestamp for checking whether speed has been held at 116 | * or above the selected frequency for a minimum of min_sample_time, 117 | * if not boosted to hispeed_freq. If boosted to hispeed_freq then we 118 | * allow the speed to drop as soon as the boostpulse duration expires 119 | * (or the indefinite boost is turned off). If policy->max is restored 120 | * for max_freq_hysteresis, don't extend the timestamp. Otherwise, it 121 | * could incorrectly extended the duration of max_freq_hysteresis by 122 | * min_sample_time. 123 | */ 124 | if ((!boosted || new_freq > tunables_.hispeed_freq) && !jump_to_max_no_ts) { 125 | floor_freq = new_freq; 126 | floor_validate_time = now; 127 | } 128 | 129 | if (new_freq >= cluster_->GetMaxfreq() && !jump_to_max_no_ts) { 130 | max_freq_hyst_start_time = now; 131 | } 132 | target_freq = new_freq; 133 | 134 | return target_freq; 135 | } 136 | 137 | int Interactive::GetAboveHispeedDelayGearNum(void) const { 138 | auto get_freq = [=](int idx) { return cluster_->model_.opp_model[idx].freq; }; 139 | 140 | const auto &t = tunables_; 141 | const int n_opp = cluster_->model_.opp_model.size(); 142 | const int n_above = std::min(ABOVE_DELAY_MAX_LEN, n_opp); 143 | 144 | int anchor_val = -1; 145 | int n_gears = 0; 146 | 147 | for (int i = 0; i < n_above; ++i) { 148 | if (get_freq(i) < t.hispeed_freq) { 149 | continue; 150 | } 151 | if (anchor_val != t.above_hispeed_delay[i]) { 152 | anchor_val = t.above_hispeed_delay[i]; 153 | n_gears++; 154 | } 155 | } 156 | 157 | return n_gears; 158 | } 159 | 160 | int Interactive::GetTargetLoadGearNum(void) const { 161 | const auto &t = tunables_; 162 | const int n_opp = cluster_->model_.opp_model.size(); 163 | const int n_targetloads = std::min(TARGET_LOAD_MAX_LEN, n_opp); 164 | 165 | int anchor_val = -1; 166 | int n_gears = 0; 167 | 168 | for (int i = 0; i < n_targetloads; ++i) { 169 | if (anchor_val != t.target_loads[i]) { 170 | anchor_val = t.target_loads[i]; 171 | n_gears++; 172 | } 173 | } 174 | 175 | return n_gears; 176 | } 177 | -------------------------------------------------------------------------------- /source/sim/interactive.h: -------------------------------------------------------------------------------- 1 | #ifndef __INTERACTIVE_H 2 | #define __INTERACTIVE_H 3 | 4 | #include 5 | 6 | #include "cpumodel.h" 7 | 8 | const int kInteractiveParamFixedLen = 4; 9 | #define TARGET_LOAD_MAX_LEN 24 10 | #define ABOVE_DELAY_MAX_LEN 32 11 | 12 | class Interactive { 13 | public: 14 | typedef struct _InteractiveTunables { 15 | int hispeed_freq; 16 | uint16_t go_hispeed_load; 17 | uint8_t min_sample_time; 18 | uint8_t max_freq_hysteresis; 19 | uint8_t above_hispeed_delay[ABOVE_DELAY_MAX_LEN]; 20 | uint8_t target_loads[TARGET_LOAD_MAX_LEN]; 21 | _InteractiveTunables(const Cluster &cm); 22 | _InteractiveTunables() {} 23 | } Tunables; 24 | 25 | Interactive() = delete; 26 | Interactive(Tunables tunables, Cluster *cm) 27 | : tunables_(tunables), 28 | cluster_(cm), 29 | target_freq(cm->model_.max_freq), 30 | floor_freq(cm->model_.max_freq), 31 | max_freq_hyst_start_time(0), 32 | hispeed_validate_time(0), 33 | floor_validate_time(0) {} 34 | 35 | int InteractiveTimer(int load, int now); 36 | int GetAboveHispeedDelayGearNum(void) const; 37 | int GetTargetLoadGearNum(void) const; 38 | 39 | Tunables GetTunables(void) { return tunables_; } 40 | void SetTunables(const Tunables &t) { tunables_ = t; } 41 | 42 | private: 43 | int freq_to_targetload(int freq) const; 44 | int freq_to_above_hispeed_delay(int freq) const; 45 | int choose_freq(int freq, int load) const; 46 | 47 | Tunables tunables_; 48 | const Cluster *cluster_; 49 | 50 | int target_freq; 51 | int floor_freq; 52 | int max_freq_hyst_start_time; 53 | int hispeed_validate_time; 54 | int floor_validate_time; 55 | }; 56 | 57 | inline int Interactive::freq_to_targetload(int freq) const { 58 | return tunables_.target_loads[std::min(TARGET_LOAD_MAX_LEN - 1, cluster_->FindFreqIdx(freq, -1, -1))]; 59 | } 60 | 61 | inline int Interactive::freq_to_above_hispeed_delay(int freq) const { 62 | return tunables_.above_hispeed_delay[std::min(ABOVE_DELAY_MAX_LEN - 1, cluster_->FindFreqIdx(freq, -1, -1))]; 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /source/sim/rank.cpp: -------------------------------------------------------------------------------- 1 | #include "rank.h" 2 | 3 | #include 4 | 5 | Rank::Score Rank::Eval(const Workload &workload, const Workload &idleload, const SimResultPack &rp, Soc soc, 6 | bool is_init) { 7 | if (is_init) { 8 | default_score_.ref_power_comsumed = InitRefBattPartition(rp.onscreen.power); 9 | } 10 | 11 | double perf = EvalPerformance(workload, soc, rp.onscreen.capacity); 12 | double work_lasting = EvalBatterylife(rp.onscreen.power); 13 | double idle_lasting = EvalIdleLasting(rp.offscreen_pwr); 14 | 15 | if (is_init) { 16 | return {perf, work_lasting, idle_lasting, default_score_.ref_power_comsumed}; 17 | } else { 18 | return {perf, work_lasting, idle_lasting, {0}}; 19 | } 20 | } 21 | 22 | double Rank::EvalPerformance(const Workload &workload, const Soc &soc, const SimSeq &capacity_log) { 23 | const int enough_capacity = soc.GetEnoughCapacity(); 24 | const int max_capacity = soc.GetMaxCapacity(); 25 | const int margin_capacity = max_capacity - enough_capacity; 26 | 27 | auto calc_lag = [=](int required, int provided) { 28 | if (provided >= max_capacity) { 29 | return 0.0; 30 | } 31 | if (provided < required) { 32 | if (provided >= enough_capacity) { 33 | return misc_.enough_penalty * (max_capacity - provided) / margin_capacity; 34 | } else { 35 | return 1.0; 36 | } 37 | } else { 38 | return 0.0; 39 | } 40 | return 0.0; 41 | }; 42 | 43 | LagSeq common_lag_seq; 44 | common_lag_seq.reserve(capacity_log.size()); 45 | 46 | auto iter_log = capacity_log.begin(); 47 | for (const auto &loadslice : workload.windowed_load_) { 48 | common_lag_seq.push_back(calc_lag(loadslice.max_load, *iter_log++)); 49 | } 50 | 51 | LagSeq render_lag_seq; 52 | render_lag_seq.reserve(workload.render_load_.size()); 53 | 54 | for (const auto &r : workload.render_load_) { 55 | uint64_t aggreated_capacity = 0; 56 | aggreated_capacity += capacity_log[r.window_idxs[0]] * r.window_quantums[0]; 57 | aggreated_capacity += capacity_log[r.window_idxs[1]] * r.window_quantums[1]; 58 | aggreated_capacity += capacity_log[r.window_idxs[2]] * r.window_quantums[2]; 59 | aggreated_capacity /= workload.frame_quantum_; 60 | render_lag_seq.push_back(calc_lag(r.frame_load, aggreated_capacity)); 61 | } 62 | 63 | double common_lag_ratio = PerfPartitionEval(common_lag_seq); 64 | double render_lag_ratio = PerfPartitionEval(render_lag_seq); 65 | 66 | double score = misc_.render_fraction * render_lag_ratio + misc_.common_fraction * common_lag_ratio; 67 | // double score = render_lag_ratio; 68 | 69 | return (score / default_score_.performance); 70 | } 71 | 72 | double Rank::PerfPartitionEval(const LagSeq &lag_seq) const { 73 | const int partition_len = misc_.perf_partition_len; 74 | const int n_partition = lag_seq.size() / partition_len; 75 | 76 | const int &seq_lag_l1 = misc_.seq_lag_l1; 77 | const int &seq_lag_l2 = misc_.seq_lag_l2; 78 | const int &seq_lag_max = misc_.seq_lag_max; 79 | 80 | const double &seq_l0_scale = misc_.seq_lag_l0_scale; 81 | const double &seq_l1_scale = misc_.seq_lag_l1_scale; 82 | const double &seq_l2_scale = misc_.seq_lag_l2_scale; 83 | 84 | LagSeq period_lag_arr; 85 | period_lag_arr.reserve(n_partition); 86 | 87 | int cnt = 1; 88 | int n_recent_lag = 0; 89 | float period_lag_score = 0.0; 90 | for (const auto &lag_scale : lag_seq) { 91 | bool is_lag = (lag_scale > 0); 92 | if (cnt == partition_len) { 93 | period_lag_arr.push_back(period_lag_score); 94 | period_lag_score = 0.0; 95 | cnt = 0; 96 | } 97 | if (!is_lag) { 98 | n_recent_lag = n_recent_lag >> 1; 99 | } 100 | n_recent_lag = std::min(seq_lag_max, n_recent_lag + is_lag); 101 | 102 | period_lag_score += seq_l0_scale * lag_scale * (n_recent_lag > 0); 103 | period_lag_score += seq_l1_scale * lag_scale * (n_recent_lag >= seq_lag_l1); 104 | period_lag_score += seq_l2_scale * lag_scale * (n_recent_lag >= seq_lag_l2); 105 | ++cnt; 106 | } 107 | 108 | double sum = 0; 109 | for (const auto &l : period_lag_arr) { 110 | sum += l * l; 111 | } 112 | 113 | return std::sqrt(sum / n_partition); 114 | } 115 | 116 | double Rank::EvalBatterylife(const SimSeq &power_log) const { 117 | double partitional = BattPartitionEval(power_log); 118 | return (1.0 / (partitional * default_score_.battery_life)); 119 | } 120 | 121 | double Rank::BattPartitionEval(const SimSeq &power_seq) const { 122 | const int partition_len = misc_.batt_partition_len; 123 | const int n_partition = power_seq.size() / partition_len; 124 | 125 | std::vector period_power_arr; 126 | period_power_arr.reserve(n_partition); 127 | 128 | int cnt = 1; 129 | uint64_t period_power_comsumed = 0; 130 | for (const auto &power_comsumed : power_seq) { 131 | if (cnt == partition_len) { 132 | period_power_arr.push_back(period_power_comsumed); 133 | period_power_comsumed = 0; 134 | cnt = 0; 135 | } 136 | period_power_comsumed += power_comsumed; 137 | ++cnt; 138 | } 139 | 140 | double sum = 0; 141 | for (int i = 0; i < n_partition; ++i) { 142 | double t = (double)period_power_arr[i] / default_score_.ref_power_comsumed[i]; 143 | sum += t * t; 144 | } 145 | 146 | return std::sqrt(sum / n_partition); 147 | } 148 | 149 | std::vector Rank::InitRefBattPartition(const SimSeq &power_seq) const { 150 | const int partition_len = misc_.batt_partition_len; 151 | const int n_partition = power_seq.size() / partition_len; 152 | 153 | std::vector period_power_arr; 154 | period_power_arr.reserve(n_partition); 155 | 156 | int cnt = 1; 157 | uint64_t period_power_comsumed = 0; 158 | for (const auto &power_comsumed : power_seq) { 159 | if (cnt == partition_len) { 160 | period_power_arr.push_back(period_power_comsumed); 161 | period_power_comsumed = 0; 162 | cnt = 0; 163 | } 164 | period_power_comsumed += power_comsumed; 165 | ++cnt; 166 | } 167 | 168 | return period_power_arr; 169 | } 170 | 171 | // double Rank::CalcComplexity(const Interactive &little, const Interactive &big) const { 172 | // const int kAboveMinLen = 10; 173 | // const int kTargetloadMinLen = 10; 174 | 175 | // double clpx[4] = {0.0, 0.0, 0.0, 0.0}; 176 | // int i = 0; 177 | 178 | // clpx[i++] = std::max(kAboveMinLen, little.GetAboveHispeedDelayGearNum()) / (double)kAboveMinLen; 179 | // clpx[i++] = std::max(kTargetloadMinLen, little.GetTargetLoadGearNum()) / (double)kTargetloadMinLen; 180 | // clpx[i++] = std::max(kAboveMinLen, big.GetAboveHispeedDelayGearNum()) / (double)kAboveMinLen; 181 | // clpx[i++] = std::max(kTargetloadMinLen, big.GetTargetLoadGearNum()) / (double)kTargetloadMinLen; 182 | 183 | // double sum = 0.0; 184 | // for (const auto &n : clpx) { 185 | // sum += n * n; 186 | // } 187 | 188 | // return std::sqrt(sum / 4); 189 | // } 190 | -------------------------------------------------------------------------------- /source/sim/rank.h: -------------------------------------------------------------------------------- 1 | #ifndef __RANK_H 2 | #define __RANK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "cpumodel.h" 8 | #include "sim_types.h" 9 | #include "workload.h" 10 | 11 | // 评分 12 | class Rank { 13 | public: 14 | #define POWER_SHIFT 4 15 | 16 | typedef struct _Score { 17 | double performance; 18 | double battery_life; 19 | double idle_lasting; 20 | std::vector ref_power_comsumed; 21 | } Score; 22 | 23 | typedef struct _MiscConst { 24 | double render_fraction; 25 | double common_fraction; 26 | double complexity_fraction; 27 | int perf_partition_len; 28 | int seq_lag_l1; 29 | int seq_lag_l2; 30 | int seq_lag_max; 31 | double seq_lag_l0_scale; 32 | double seq_lag_l1_scale; 33 | double seq_lag_l2_scale; 34 | double enough_penalty; 35 | int batt_partition_len; 36 | } MiscConst; 37 | 38 | using LagSeq = std::vector; 39 | 40 | Rank() = delete; 41 | Rank(const Score &default_score, const MiscConst &misc) : misc_(misc), default_score_(default_score){}; 42 | Score Eval(const Workload &workload, const Workload &idleload, const SimResultPack &rp, Soc soc, bool is_init); 43 | 44 | private: 45 | int QuantifyPower(int power) const { return (power >> POWER_SHIFT); } 46 | 47 | void AdaptLoad(int &load, int capacity) const { load = std::min(load, capacity); } 48 | void AdaptLoad(int *loads, int n_loads, int capacity) const { 49 | for (int i = 0; i < n_loads; ++i) { 50 | loads[i] = std::min(loads[i], capacity); 51 | } 52 | } 53 | 54 | double PerfPartitionEval(const LagSeq &lag_seq) const; 55 | double BattPartitionEval(const SimSeq &power_seq) const; 56 | 57 | double EvalPerformance(const Workload &workload, const Soc &soc, const SimSeq &capacity_log); 58 | double EvalBatterylife(const SimSeq &power_log) const; 59 | 60 | std::vector InitRefBattPartition(const SimSeq &power_seq) const; 61 | 62 | double EvalIdleLasting(uint64_t idle_power_comsumed) const { 63 | return (1.0 / (idle_power_comsumed * default_score_.idle_lasting)); 64 | } 65 | 66 | MiscConst misc_; 67 | Score default_score_; 68 | }; 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /source/sim/sim.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __SIM_H 2 | #define __SIM_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "cpumodel.h" 11 | #include "sim_types.h" 12 | #include "workload.h" 13 | 14 | template 15 | struct GovernorTs { 16 | typename GovernorT::Tunables t[2]; 17 | }; 18 | 19 | // 仿真运行 20 | template 21 | class Sim { 22 | public: 23 | #define POWER_SHIFT 4 24 | 25 | typedef struct _Tunables { 26 | GovernorTs governor; 27 | typename SchedT::Tunables sched; 28 | typename BoostT::Tunables boost; 29 | bool has_boost; 30 | } Tunables; 31 | 32 | typedef struct _MiscConst { 33 | int working_base_mw; 34 | int idle_base_mw; 35 | } MiscConst; 36 | 37 | using Governor = GovernorT; 38 | using Sched = SchedT; 39 | using Boost = BoostT; 40 | 41 | Sim() = delete; 42 | Sim(const Tunables &tunables, const MiscConst &misc) : tunables_(tunables), misc_(misc){}; 43 | 44 | // 仿真运行,得到亮屏考察每一时间片的性能输出和功耗,以及灭屏的总耗电 45 | void Run(const Workload &workload, const Workload &idleload, Soc soc, SimResultPack *rp) { 46 | // 常量计算 47 | const int cl_little_idx = soc.GetLittleClusterIdx(); 48 | const int cl_big_idx = soc.GetBigClusterIdx(); 49 | const int base_pwr = misc_.working_base_mw * 100; 50 | const int idle_base_pwr = misc_.idle_base_mw * 100; 51 | 52 | // 使用参数实例化CPU调速器仿真 53 | auto little_governor = GovernorT(tunables_.governor.t[cl_little_idx], &soc.clusters_[cl_little_idx]); 54 | auto big_governor = GovernorT(tunables_.governor.t[cl_big_idx], &soc.clusters_[cl_big_idx]); 55 | 56 | // 使用参数实例化调度器仿真 57 | typename SchedT::Cfg sched_cfg; 58 | sched_cfg.tunables = tunables_.sched; 59 | sched_cfg.little = &soc.clusters_[cl_little_idx]; 60 | sched_cfg.big = &soc.clusters_[cl_big_idx]; 61 | sched_cfg.governor_little = &little_governor; 62 | sched_cfg.governor_big = &big_governor; 63 | SchedT sched(sched_cfg); 64 | 65 | // 使用参数实例化输入升频 66 | BoostT boost; 67 | if (tunables_.has_boost) { 68 | typename BoostT::SysEnv boost_env; 69 | boost_env.soc = &soc; 70 | boost_env.little = &little_governor; 71 | boost_env.big = &big_governor; 72 | boost_env.sched = &sched; 73 | boost = BoostT(tunables_.boost, boost_env); 74 | } 75 | 76 | int quantum_cnt = 0; 77 | int capacity = soc.clusters_[0].CalcCapacity(); 78 | 79 | // 亮屏考察每一时间片的性能输出和功耗 80 | auto &capacity_log = rp->onscreen.capacity; 81 | auto &power_log = rp->onscreen.power; 82 | for (Workload::LoadSlice w : workload.windowed_load_) { 83 | AdaptLoad(w.max_load, capacity); 84 | AdaptLoad(w.load, workload.core_num_, capacity); 85 | capacity_log.push_back(capacity); 86 | power_log.push_back(base_pwr + sched.CalcPower(w.load)); 87 | 88 | boost.Tick(w.has_input_event, w.has_render, quantum_cnt); 89 | capacity = sched.SchedulerTick(w.max_load, w.load, workload.core_num_, quantum_cnt); 90 | quantum_cnt++; 91 | } 92 | 93 | // 灭屏只计算耗电总和,不考察是否卡顿 94 | rp->offscreen_pwr = idle_base_pwr * idleload.windowed_load_.size(); 95 | for (Workload::LoadSlice w : idleload.windowed_load_) { 96 | AdaptLoad(w.max_load, capacity); 97 | AdaptLoad(w.load, idleload.core_num_, capacity); 98 | rp->offscreen_pwr += sched.CalcPowerForIdle(w.load); 99 | 100 | boost.Tick(w.has_input_event, w.has_render, quantum_cnt); 101 | capacity = sched.SchedulerTick(w.max_load, w.load, idleload.core_num_, quantum_cnt); 102 | quantum_cnt++; 103 | } 104 | 105 | return; 106 | } 107 | 108 | private: 109 | // 根据当前性能输出限幅输入的性能需求,不可能输入高于100%的负载 110 | void AdaptLoad(int &load, int capacity) const { load = std::min(load, capacity); } 111 | // 根据当前性能输出限幅输入的性能需求,不可能输入高于100%的负载 112 | void AdaptLoad(int *loads, int n_loads, int capacity) const { 113 | for (int i = 0; i < n_loads; ++i) { 114 | loads[i] = std::min(loads[i], capacity); 115 | } 116 | } 117 | 118 | Tunables tunables_; 119 | MiscConst misc_; 120 | }; 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /source/sim/sim_types.h: -------------------------------------------------------------------------------- 1 | #ifndef __SIM_TYPES_H 2 | #define __SIM_TYPES_H 3 | 4 | #include 5 | #include 6 | 7 | typedef std::vector SimSeq; 8 | 9 | typedef struct _SimResult { 10 | SimSeq capacity; 11 | SimSeq power; 12 | } SimResult; 13 | 14 | typedef struct _SimResultPack { 15 | SimResult onscreen; 16 | uint64_t offscreen_pwr; 17 | } SimResultPack; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /source/sim/workload.cpp: -------------------------------------------------------------------------------- 1 | #include "workload.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "json.hpp" 7 | 8 | Workload::Workload(const std::string &workload_file) { 9 | std::ifstream ifs(workload_file); 10 | if (!ifs.good()) { 11 | using namespace std; 12 | cout << "Workload access ERROR: " << workload_file << endl; 13 | throw runtime_error("file access error"); 14 | } 15 | 16 | nlohmann::json j; 17 | ifs >> j; 18 | quantum_sec_ = j["quantumSec"]; 19 | window_quantum_ = j["windowQuantum"]; 20 | frame_quantum_ = j["frameQuantum"]; 21 | efficiency_ = j["efficiency"]; 22 | freq_ = j["freq"]; 23 | load_scale_ = j["loadScale"]; 24 | core_num_ = j["coreNum"]; 25 | 26 | for (const auto &src_name : j["src"]) { 27 | src_.push_back(src_name); 28 | } 29 | 30 | auto loadpct_to_demand = [=](int load) { return kWorkloadScaleFactor * freq_ * efficiency_ * load; }; 31 | 32 | if (j["renderLoad"].size() == 0) { 33 | using namespace std; 34 | cout << "renderLoad is empty: " << workload_file << endl; 35 | throw runtime_error("renderLoad is empty"); 36 | } 37 | 38 | auto next_win_q = [=](int q) { return (q / window_quantum_ + 1) * window_quantum_; }; 39 | render_load_.reserve(j["renderLoad"].size()); 40 | for (const auto &render_demand : j["renderLoad"]) { 41 | RenderSlice r; 42 | memset(&r, 0, sizeof(RenderSlice)); 43 | 44 | int begin_q = render_demand[0]; 45 | int end_q = begin_q + frame_quantum_; 46 | int idx_rec = 0; 47 | int left_q = begin_q; 48 | int right_q = next_win_q(begin_q); 49 | while (left_q != right_q) { 50 | r.window_idxs[idx_rec] = left_q / window_quantum_; 51 | r.window_quantums[idx_rec] = right_q - left_q; 52 | left_q = right_q; 53 | right_q = std::min(end_q, next_win_q(right_q)); 54 | idx_rec++; 55 | } 56 | r.frame_load = loadpct_to_demand(render_demand[1]); 57 | 58 | render_load_.push_back(r); 59 | } 60 | 61 | if (j["windowedLoad"].size() == 0) { 62 | using namespace std; 63 | cout << "windowedLoad is empty: " << workload_file << endl; 64 | throw runtime_error("windowedLoad is empty"); 65 | } 66 | 67 | auto has_render = [&](int idx) { 68 | for (const auto &r : render_load_) { 69 | if (r.window_idxs[0] == idx || r.window_idxs[1] == idx || r.window_idxs[2] == idx) 70 | return true; 71 | } 72 | return false; 73 | }; 74 | 75 | windowed_load_.reserve(j["windowedLoad"].size()); 76 | for (const auto &slice : j["windowedLoad"]) { 77 | LoadSlice l; 78 | memset(&l, 0, sizeof(LoadSlice)); 79 | 80 | l.max_load = loadpct_to_demand(slice[0]); 81 | for (int idx = 0; idx < core_num_; ++idx) { 82 | l.load[idx] = loadpct_to_demand(slice[idx + 1]); 83 | } 84 | // 按降序排列,对于骁龙82x这种2+2的平台只会使用前2个负载值 85 | std::sort(&l.load[0], &l.load[3], std::greater()); 86 | l.has_input_event = slice[core_num_ + 1]; 87 | l.has_render = has_render(windowed_load_.size()); 88 | 89 | windowed_load_.push_back(l); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /source/sim/workload.h: -------------------------------------------------------------------------------- 1 | #ifndef __WORKLOAD_H 2 | #define __WORKLOAD_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | class Workload { 10 | public: 11 | typedef struct _LoadSlice { 12 | int max_load; 13 | int load[4]; 14 | int has_input_event; 15 | int has_render; 16 | } LoadSlice; 17 | 18 | typedef struct _RenderSlice { 19 | int window_idxs[3]; 20 | int window_quantums[3]; 21 | int frame_load; 22 | } RenderSlice; 23 | 24 | Workload(const std::string &workload_file); 25 | 26 | const float kWorkloadScaleFactor = 1.15; 27 | std::vector windowed_load_; 28 | std::vector render_load_; 29 | std::vector src_; 30 | float quantum_sec_; 31 | int window_quantum_; 32 | int frame_quantum_; 33 | int efficiency_; 34 | int freq_; 35 | int load_scale_; 36 | int core_num_; 37 | 38 | private: 39 | Workload(); 40 | }; 41 | 42 | #endif -------------------------------------------------------------------------------- /source/utils/misc.h: -------------------------------------------------------------------------------- 1 | #ifndef __MISC_H 2 | #define __MISC_H 3 | 4 | #include 5 | 6 | inline int Ms2Us(int ms) { 7 | return (1000 * ms); 8 | } 9 | 10 | inline int Mhz2kHz(int mhz) { 11 | return (1000 * mhz); 12 | } 13 | 14 | inline double Double2Pct(double d) { 15 | return (d * 100); 16 | } 17 | 18 | inline int Quantum2Ms(int n_quantum) { 19 | return (n_quantum * 10); 20 | } 21 | 22 | inline bool Replace(std::string &str, const std::string &from, const std::string &to) { 23 | size_t start_pos = str.find(from); 24 | if (start_pos == std::string::npos) 25 | return false; 26 | str.replace(start_pos, from.length(), to); 27 | return true; 28 | } 29 | 30 | inline void ReplaceAll(std::string &str, const std::string &from, const std::string &to) { 31 | if (from.empty()) 32 | return; 33 | size_t start_pos = 0; 34 | while ((start_pos = str.find(from, start_pos)) != std::string::npos) { 35 | str.replace(start_pos, from.length(), to); 36 | start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' 37 | } 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /template/powercfg_template.sh: -------------------------------------------------------------------------------- 1 | #!/system/bin/sh 2 | # [project_name] [github_url] 3 | # Author: [yourname] 4 | # Platform: [platform_name] 5 | # Generated at: [generated_time] 6 | 7 | CUR_LEVEL_FILE="/cache/.wipe_cur_level" 8 | PARAM_BAK_FILE="/cache/.wipe_param_bak" 9 | 10 | # const variables 11 | PARAM_NUM=[param_num] 12 | 13 | # sysfs_objx example: 14 | # sysfs_obj1="${C0_GOVERNOR_DIR}/target_loads" 15 | [sysfs_obj] 16 | 17 | # level x example: 18 | # lag percent: 90.0% 19 | # battery life: 110.0% 20 | # levelx_val1="38000" 21 | # levelx_val2="85 1190000:90" 22 | 23 | # LEVEL 0 24 | [level0] 25 | # LEVEL 1 26 | [level1] 27 | # LEVEL 2 28 | [level2] 29 | # LEVEL 3 30 | [level3] 31 | # LEVEL 4 32 | [level4] 33 | # LEVEL 5 34 | [level5] 35 | # LEVEL 6 36 | [level6] 37 | 38 | # global variables 39 | HAS_BAK=0 40 | NOT_MATCH_NUM=0 41 | 42 | # $1:value $2:file path 43 | lock_value() 44 | { 45 | if [ -f ${2} ]; then 46 | chmod 0666 ${2} 47 | echo ${1} > ${2} 48 | chmod 0444 ${2} 49 | fi 50 | } 51 | 52 | # $1:level_number 53 | apply_level() 54 | { 55 | # 1. backup 56 | backup_default 57 | # 2. apply modification 58 | for n in `seq ${PARAM_NUM}` 59 | do 60 | eval obj="$"sysfs_obj${n} 61 | eval val="$"level${1}_val${n} 62 | lock_value "${val}" ${obj} 63 | done 64 | # 3. save current level to file 65 | echo ${1} > ${CUR_LEVEL_FILE} 66 | } 67 | 68 | # $1:value $2:file path 69 | check_value() 70 | { 71 | if [ -f ${2} ]; then 72 | expected="${1}" 73 | actual="`cat ${2}`" 74 | if [ "${actual}" != "${expected}" ]; then 75 | # input_boost_freq has a additional line break 76 | case1=$(echo "${actual}" | grep "${expected}") 77 | # Actual scaling_min_freq is 633600, but given is 633000. That's OK 78 | case2=$(echo "${2}" | grep -E "scaling_m.{2}_freq$") 79 | # skip msm_performance/parameters: cpu_min_freq and cpu_max_freq 80 | case3=$(echo "${2}" | grep -E "cpu_m.{2}_freq$") 81 | if [ "${case1}" == "" ] && [ "${case2}" == "" ] && [ "${case3}" == "" ]; then 82 | NOT_MATCH_NUM=$(expr ${NOT_MATCH_NUM} + 1) 83 | echo "[FAIL] ${2}" 84 | echo "expected: ${expected}" 85 | echo "actual: ${actual}" 86 | fi 87 | fi 88 | else 89 | echo "[IGNORE] ${2}" 90 | fi 91 | } 92 | 93 | # $1:level_number 94 | verify_level() 95 | { 96 | for n in `seq ${PARAM_NUM}` 97 | do 98 | eval obj="$"sysfs_obj${n} 99 | eval val="$"level${1}_val${n} 100 | check_value "${val}" ${obj} 101 | done 102 | echo "Verified ${PARAM_NUM} parameters, ${NOT_MATCH_NUM} FAIL" 103 | } 104 | 105 | backup_default() 106 | { 107 | if [ ${HAS_BAK} -eq 0 ]; then 108 | # clear previous backup file 109 | echo "" > ${PARAM_BAK_FILE} 110 | for n in `seq ${PARAM_NUM}` 111 | do 112 | eval obj="$"sysfs_obj${n} 113 | echo "bak_obj${n}=${obj}" >> ${PARAM_BAK_FILE} 114 | echo "bak_val${n}=\"`cat ${obj}`\"" >> ${PARAM_BAK_FILE} 115 | done 116 | echo "Backup default parameters has completed." 117 | else 118 | echo "Backup file already exists, skip backup." 119 | fi 120 | } 121 | 122 | restore_default() 123 | { 124 | if [ -f ${PARAM_BAK_FILE} ]; then 125 | # read backup variables 126 | while read line 127 | do 128 | eval ${line} 129 | done < ${PARAM_BAK_FILE} 130 | # set backup variables 131 | for n in `seq ${PARAM_NUM}` 132 | do 133 | eval obj="$"bak_obj${n} 134 | eval val="$"bak_val${n} 135 | lock_value "${val}" ${obj} 136 | done 137 | echo "Restore OK" 138 | else 139 | echo "Backup file for default parameters not found." 140 | echo "Restore FAIL" 141 | fi 142 | } 143 | 144 | permanently_disable_perfd() 145 | { 146 | stop perfd 147 | perfd_path=`which perfd` 148 | if [ -n "${perfd_path}" ]; then 149 | mv ${perfd_path} `dirname ${perfd_path}`/perfd_bak 150 | echo "Perfd has been disabled." 151 | else 152 | echo "Perfd binary not found." 153 | fi 154 | } 155 | 156 | permanently_enable_perfd() 157 | { 158 | perfd_bak_path=`which perfd_bak` 159 | if [ -n "${perfd_bak_path}" ]; then 160 | mv ${perfd_bak_path} `dirname ${perfd_bak_path}`/perfd 161 | echo "Perfd has been enabled." 162 | else 163 | echo "Perfd_bak binary not found." 164 | fi 165 | start perfd 166 | } 167 | 168 | # suppress stderr 169 | ( 170 | 171 | echo "" 172 | 173 | # backup runonce flag 174 | if [ -f ${PARAM_BAK_FILE} ]; then 175 | HAS_BAK=1 176 | fi 177 | 178 | action=$1 179 | # default option is balance 180 | if [ ! -n "$action" ]; then 181 | action="balance" 182 | fi 183 | 184 | if [ "$action" = "debug" ]; then 185 | echo "[project_name] [github_url]" 186 | echo "Author: [yourname]" 187 | echo "Platform: [platform_name]" 188 | echo "Generated at: [generated_time]" 189 | echo "" 190 | # perform parameter verification 191 | cur_level=`cat ${CUR_LEVEL_FILE}` 192 | if [ -n "${cur_level}" ]; then 193 | echo "Current level: ${cur_level}" 194 | verify_level ${cur_level} 195 | else 196 | echo "Current level: not detected" 197 | fi 198 | echo "" 199 | exit 0 200 | fi 201 | 202 | if [ "$action" = "restore" ]; then 203 | restore_default 204 | rm ${CUR_LEVEL_FILE} 205 | fi 206 | 207 | if [ "$action" = "powersave" ]; then 208 | echo "Applying powersave..." 209 | apply_level 5 210 | echo "Applying powersave done." 211 | fi 212 | 213 | if [ "$action" = "balance" ]; then 214 | echo "Applying balance..." 215 | apply_level 3 216 | echo "Applying balance done." 217 | fi 218 | 219 | if [ "$action" = "performance" ]; then 220 | echo "Applying performance..." 221 | apply_level 1 222 | echo "Applying performance done." 223 | fi 224 | 225 | if [ "$action" = "fast" ]; then 226 | echo "Applying fast..." 227 | apply_level 0 228 | echo "Applying fast done." 229 | fi 230 | 231 | if [ "$action" = "level" ]; then 232 | level=${2} 233 | if [ "${level}" -ge "0" ] && [ "${level}" -le "6" ]; then 234 | echo "Applying level ${level}..." 235 | apply_level ${level} 236 | echo "Applying level ${level} done." 237 | else 238 | echo "Level ${level} not supported." 239 | fi 240 | fi 241 | 242 | if [ "$action" = "perfd" ]; then 243 | cmd=${2} 244 | if [ "${cmd}" == "enable" ]; then 245 | permanently_enable_perfd 246 | fi 247 | if [ "${cmd}" == "disable" ]; then 248 | permanently_disable_perfd 249 | fi 250 | fi 251 | 252 | echo "" 253 | 254 | # suppress stderr 255 | ) 2>/dev/null 256 | 257 | exit 0 258 | -------------------------------------------------------------------------------- /tools/migrate.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | import json 4 | import argparse 5 | 6 | need_merged_file = True 7 | raw_path = '../dataset/workload/osborn/raw/' 8 | out_path = '../dataset/workload/osborn/' 9 | n_cpu = 8 10 | trace_cpuid_low = 4 11 | trace_cpuid_high = 7 12 | # window_sec = 0.02 # 20ms timer_rate 13 | window_sec = 0.01 # 负载聚合到10ms,以适配10ms,20ms,30ms...的timer_rate 14 | quantum_sec = 0.001 # 解析序列的最小时间单位,我们不在意事件在1.2ms还是1.4ms发生的,1ms 15 | frame_sec = 0.016 # 1帧的时长,16.7ms归到16ms 16 | 17 | merged_load_seq = list() 18 | load_shift = 7 19 | load_scale = 100 # 满负载是100 20 | busy_ratio_to_load = lambda busy_ratio: int(round(busy_ratio * load_scale)) 21 | 22 | info_filename = 'info.json' 23 | info = None 24 | with open(raw_path + info_filename, 'r') as filename: 25 | info = json.load(filename) 26 | 27 | # 采集设备是 nexus 9 28 | idle_efficiency = 1638 29 | idle_freq = 2014 30 | 31 | idle_load_seq = list() 32 | with open('standby_load_20180308_from_171023.csv', 'r') as f: 33 | for line in f: 34 | idle_load_seq.append(min(100, int(line) + 5)) 35 | 36 | # 全长1000,取前800 37 | windowed_idle_load_seq = list() 38 | for demand in idle_load_seq: 39 | windowed_idle_load_seq.append([demand, demand, demand, demand, demand, 0]) 40 | 41 | # 加一个触摸事件 42 | # windowed_idle_load_seq[400][-1] = 1 43 | 44 | packed_data = { 45 | 'src': 'standby_load_20180308_from_171023.csv', 46 | 'ver': 1, 47 | 'quantumSec': quantum_sec, 48 | 'windowQuantum': int(window_sec / quantum_sec), 49 | 'frameQuantum': int(frame_sec / quantum_sec), 50 | 'efficiencyA53': 1024, 51 | 'efficiency': info['efficiency'], 52 | 'freq': info['freq'], 53 | 'loadScale': load_scale, 54 | 'coreNum': trace_cpuid_high - trace_cpuid_low + 1, 55 | 'windowedLoadLen': len(windowed_idle_load_seq), 56 | 'windowedLoad': windowed_idle_load_seq, 57 | 'renderLoad': [[0, 0],] 58 | } 59 | with open(out_path + 'idle' + '.json', 'w') as f: 60 | json.dump(packed_data, f, indent=None, separators=(',', ':')) 61 | 62 | -------------------------------------------------------------------------------- /tools/standby_load_20180308_from_171023.csv: -------------------------------------------------------------------------------- 1 | 5 2 | 0 3 | 5 4 | 0 5 | 5 6 | 9 7 | 0 8 | 0 9 | 10 10 | 4 11 | 5 12 | 0 13 | 13 14 | 0 15 | 0 16 | 10 17 | 0 18 | 9 19 | 0 20 | 14 21 | 0 22 | 15 23 | 15 24 | 4 25 | 20 26 | 42 27 | 5 28 | 5 29 | 0 30 | 0 31 | 4 32 | 5 33 | 0 34 | 18 35 | 0 36 | 0 37 | 0 38 | 0 39 | 5 40 | 0 41 | 0 42 | 10 43 | 4 44 | 5 45 | 0 46 | 10 47 | 15 48 | 13 49 | 0 50 | 19 51 | 0 52 | 10 53 | 0 54 | 5 55 | 0 56 | 5 57 | 5 58 | 9 59 | 0 60 | 13 61 | 4 62 | 5 63 | 5 64 | 0 65 | 0 66 | 0 67 | 5 68 | 5 69 | 0 70 | 5 71 | 5 72 | 5 73 | 9 74 | 0 75 | 5 76 | 5 77 | 10 78 | 9 79 | 0 80 | 10 81 | 0 82 | 0 83 | 10 84 | 5 85 | 5 86 | 9 87 | 5 88 | 9 89 | 5 90 | 0 91 | 0 92 | 4 93 | 5 94 | 9 95 | 5 96 | 5 97 | 9 98 | 10 99 | 5 100 | 4 101 | 9 102 | 5 103 | 20 104 | 0 105 | 5 106 | 47 107 | 0 108 | 0 109 | 4 110 | 15 111 | 4 112 | 5 113 | 5 114 | 0 115 | 9 116 | 5 117 | 0 118 | 9 119 | 5 120 | 0 121 | 0 122 | 4 123 | 5 124 | 10 125 | 9 126 | 5 127 | 0 128 | 5 129 | 4 130 | 5 131 | 4 132 | 0 133 | 0 134 | 5 135 | 14 136 | 9 137 | 5 138 | 5 139 | 0 140 | 25 141 | 5 142 | 5 143 | 47 144 | 0 145 | 5 146 | 0 147 | 0 148 | 14 149 | 13 150 | 5 151 | 5 152 | 5 153 | 4 154 | 5 155 | 0 156 | 4 157 | 5 158 | 0 159 | 5 160 | 0 161 | 5 162 | 9 163 | 5 164 | 0 165 | 10 166 | 0 167 | 4 168 | 5 169 | 0 170 | 0 171 | 5 172 | 9 173 | 0 174 | 9 175 | 5 176 | 0 177 | 13 178 | 0 179 | 4 180 | 5 181 | 5 182 | 10 183 | 11 184 | 0 185 | 47 186 | 25 187 | 14 188 | 13 189 | 0 190 | 0 191 | 9 192 | 0 193 | 5 194 | 4 195 | 5 196 | 4 197 | 0 198 | 0 199 | 13 200 | 14 201 | 0 202 | 5 203 | 5 204 | 13 205 | 5 206 | 0 207 | 5 208 | 5 209 | 4 210 | 9 211 | 0 212 | 4 213 | 10 214 | 14 215 | 4 216 | 0 217 | 5 218 | 5 219 | 5 220 | 0 221 | 5 222 | 4 223 | 5 224 | 9 225 | 10 226 | 0 227 | 9 228 | 5 229 | 5 230 | 9 231 | 5 232 | 0 233 | 0 234 | 5 235 | 4 236 | 0 237 | 4 238 | 5 239 | 13 240 | 10 241 | 5 242 | 0 243 | 0 244 | 5 245 | 4 246 | 5 247 | 0 248 | 5 249 | 10 250 | 5 251 | 9 252 | 5 253 | 4 254 | 5 255 | 9 256 | 10 257 | 0 258 | 5 259 | 5 260 | 25 261 | 5 262 | 9 263 | 61 264 | 5 265 | 9 266 | 9 267 | 5 268 | 5 269 | 0 270 | 0 271 | 5 272 | 0 273 | 4 274 | 0 275 | 9 276 | 17 277 | 0 278 | 9 279 | 0 280 | 5 281 | 0 282 | 0 283 | 13 284 | 0 285 | 5 286 | 5 287 | 0 288 | 5 289 | 5 290 | 9 291 | 17 292 | 0 293 | 0 294 | 13 295 | 0 296 | 5 297 | 15 298 | 15 299 | 5 300 | 33 301 | 30 302 | 13 303 | 9 304 | 0 305 | 10 306 | 0 307 | 0 308 | 5 309 | 4 310 | 0 311 | 0 312 | 14 313 | 0 314 | 0 315 | 10 316 | 0 317 | 5 318 | 5 319 | 10 320 | 5 321 | 0 322 | 0 323 | 5 324 | 0 325 | 10 326 | 4 327 | 5 328 | 0 329 | 0 330 | 10 331 | 0 332 | 4 333 | 14 334 | 10 335 | 11 336 | 10 337 | 22 338 | 80 339 | 0 340 | 0 341 | 0 342 | 14 343 | 9 344 | 9 345 | 9 346 | 0 347 | 5 348 | 9 349 | 5 350 | 5 351 | 0 352 | 4 353 | 0 354 | 9 355 | 0 356 | 5 357 | 0 358 | 0 359 | 14 360 | 0 361 | 5 362 | 0 363 | 5 364 | 5 365 | 13 366 | 10 367 | 0 368 | 15 369 | 5 370 | 0 371 | 42 372 | 11 373 | 0 374 | 5 375 | 9 376 | 10 377 | 0 378 | 5 379 | 5 380 | 13 381 | 5 382 | 4 383 | 9 384 | 5 385 | 5 386 | 0 387 | 5 388 | 0 389 | 5 390 | 4 391 | 5 392 | 9 393 | 0 394 | 5 395 | 4 396 | 0 397 | 10 398 | 0 399 | 0 400 | 5 401 | 9 402 | 5 403 | 15 404 | 5 405 | 5 406 | 25 407 | 5 408 | 0 409 | 5 410 | 0 411 | 5 412 | 5 413 | 0 414 | 10 415 | 0 416 | 0 417 | 13 418 | 5 419 | 0 420 | 15 421 | 0 422 | 18 423 | 0 424 | 0 425 | 0 426 | 5 427 | 5 428 | 5 429 | 15 430 | 10 431 | 9 432 | 25 433 | 0 434 | 0 435 | 0 436 | 0 437 | 9 438 | 10 439 | 5 440 | 5 441 | 0 442 | 9 443 | 5 444 | 9 445 | 0 446 | 9 447 | 0 448 | 5 449 | 0 450 | 5 451 | 5 452 | 15 453 | 10 454 | 9 455 | 27 456 | 14 457 | 0 458 | 0 459 | 9 460 | 5 461 | 5 462 | 5 463 | 0 464 | 0 465 | 0 466 | 43 467 | 5 468 | 9 469 | 0 470 | 4 471 | 9 472 | 0 473 | 0 474 | 9 475 | 0 476 | 4 477 | 0 478 | 5 479 | 5 480 | 5 481 | 14 482 | 0 483 | 10 484 | 4 485 | 9 486 | 0 487 | 5 488 | 10 489 | 5 490 | 0 491 | 5 492 | 0 493 | 10 494 | 10 495 | 4 496 | 9 497 | 0 498 | 4 499 | 5 500 | 0 501 | 5 502 | 5 503 | 10 504 | 5 505 | 5 506 | 14 507 | 14 508 | 10 509 | 9 510 | 0 511 | 5 512 | 5 513 | 0 514 | 0 515 | 9 516 | 0 517 | 5 518 | 13 519 | 18 520 | 10 521 | 0 522 | 13 523 | 0 524 | 5 525 | 0 526 | 5 527 | 5 528 | 10 529 | 5 530 | 5 531 | 18 532 | 14 533 | 10 534 | 19 535 | 5 536 | 5 537 | 13 538 | 0 539 | 0 540 | 5 541 | 5 542 | 10 543 | 10 544 | 14 545 | 14 546 | 14 547 | 5 548 | 9 549 | 15 550 | 5 551 | 5 552 | 5 553 | 0 554 | 5 555 | 9 556 | 5 557 | 14 558 | 13 559 | 10 560 | 5 561 | 14 562 | 5 563 | 10 564 | 5 565 | 0 566 | 5 567 | 9 568 | 10 569 | 5 570 | 14 571 | 18 572 | 9 573 | 10 574 | 10 575 | 5 576 | 5 577 | 5 578 | 0 579 | 5 580 | 5 581 | 10 582 | 14 583 | 10 584 | 9 585 | 14 586 | 14 587 | 9 588 | 0 589 | 0 590 | 10 591 | 0 592 | 5 593 | 0 594 | 27 595 | 5 596 | 18 597 | 10 598 | 10 599 | 9 600 | 5 601 | 5 602 | 13 603 | 0 604 | 5 605 | 5 606 | 5 607 | 14 608 | 19 609 | 14 610 | 14 611 | 5 612 | 14 613 | 10 614 | 15 615 | 0 616 | 10 617 | 5 618 | 5 619 | 5 620 | 15 621 | 5 622 | 21 623 | 5 624 | 15 625 | 0 626 | 10 627 | 5 628 | 5 629 | 10 630 | 10 631 | 15 632 | 15 633 | 10 634 | 23 635 | 19 636 | 5 637 | 9 638 | 5 639 | 5 640 | 15 641 | 0 642 | 10 643 | 5 644 | 10 645 | 10 646 | 5 647 | 14 648 | 14 649 | 15 650 | 5 651 | 9 652 | 0 653 | 14 654 | 10 655 | 0 656 | 0 657 | 10 658 | 5 659 | 14 660 | 5 661 | 10 662 | 10 663 | 0 664 | 0 665 | 10 666 | 5 667 | 5 668 | 5 669 | 5 670 | 15 671 | 15 672 | 9 673 | 19 674 | 9 675 | 0 676 | 10 677 | 5 678 | 5 679 | 5 680 | 0 681 | 10 682 | 5 683 | 5 684 | 10 685 | 10 686 | 10 687 | 0 688 | 14 689 | 5 690 | 9 691 | 0 692 | 5 693 | 0 694 | 5 695 | 0 696 | 5 697 | 10 698 | 10 699 | 13 700 | 5 701 | 10 702 | 5 703 | 10 704 | 5 705 | 0 706 | 0 707 | 0 708 | 0 709 | 4 710 | 10 711 | 10 712 | 5 713 | 14 714 | 10 715 | 10 716 | 5 717 | 9 718 | 0 719 | 5 720 | 14 721 | 5 722 | 10 723 | 5 724 | 21 725 | 5 726 | 0 727 | 5 728 | 14 729 | 5 730 | 14 731 | 5 732 | 5 733 | 5 734 | 0 735 | 10 736 | 13 737 | 10 738 | 10 739 | 5 740 | 10 741 | 0 742 | 5 743 | 0 744 | 18 745 | 0 746 | 14 747 | 5 748 | 10 749 | 14 750 | 20 751 | 0 752 | 14 753 | 10 754 | 0 755 | 10 756 | 5 757 | 0 758 | 10 759 | 10 760 | 5 761 | 10 762 | 14 763 | 5 764 | 5 765 | 9 766 | 0 767 | 10 768 | 0 769 | 5 770 | 0 771 | 10 772 | 14 773 | 9 774 | 19 775 | 5 776 | 5 777 | 10 778 | 0 779 | 5 780 | 5 781 | 15 782 | 0 783 | 5 784 | 0 785 | 10 786 | 14 787 | 14 788 | 5 789 | 5 790 | 0 791 | 5 792 | 15 793 | 5 794 | 5 795 | 14 796 | 0 797 | 10 798 | 5 799 | 10 800 | 10 801 | 5 802 | 5 803 | 10 804 | 5 805 | 5 806 | 14 807 | 14 808 | 10 809 | 9 810 | 0 811 | 5 812 | 5 813 | 0 814 | 0 815 | 9 816 | 0 817 | 5 818 | 13 819 | 18 820 | 10 821 | 0 822 | 13 823 | 0 824 | 5 825 | 0 826 | 5 827 | 5 828 | 10 829 | 5 830 | 5 831 | 18 832 | 14 833 | 10 834 | 19 835 | 5 836 | 5 837 | 13 838 | 0 839 | 0 840 | 5 841 | 5 842 | 10 843 | 10 844 | 14 845 | 14 846 | 14 847 | 5 848 | 9 849 | 15 850 | 5 851 | 5 852 | 5 853 | 0 854 | 5 855 | 9 856 | 5 857 | 14 858 | 13 859 | 10 860 | 5 861 | 14 862 | 5 863 | 10 864 | 5 865 | 0 866 | 5 867 | 9 868 | 10 869 | 5 870 | 14 871 | 18 872 | 9 873 | 10 874 | 10 875 | 5 876 | 5 877 | 5 878 | 0 879 | 5 880 | 5 881 | 10 882 | 14 883 | 10 884 | 9 885 | 14 886 | 14 887 | 9 888 | 0 889 | 0 890 | 10 891 | 0 892 | 5 893 | 0 894 | 27 895 | 5 896 | 18 897 | 10 898 | 10 899 | 9 900 | 5 901 | 5 902 | 13 903 | 0 904 | 5 905 | 5 906 | 5 907 | 14 908 | 19 909 | 14 910 | 14 911 | 5 912 | 14 913 | 10 914 | 15 915 | 0 916 | 10 917 | 5 918 | 5 919 | 5 920 | 15 921 | 5 922 | 21 923 | 5 924 | 15 925 | 0 926 | 10 927 | 5 928 | 5 929 | 10 930 | 10 931 | 15 932 | 15 933 | 10 934 | 23 935 | 19 936 | 5 937 | 9 938 | 5 939 | 5 940 | 15 941 | 0 942 | 10 943 | 5 944 | 10 945 | 10 946 | 5 947 | 14 948 | 14 949 | 15 950 | 5 951 | 9 952 | 0 953 | 14 954 | 10 955 | 0 956 | 0 957 | 10 958 | 5 959 | 14 960 | 5 961 | 10 962 | 10 963 | 0 964 | 0 965 | 10 966 | 5 967 | 5 968 | 5 969 | 5 970 | 15 971 | 15 972 | 9 973 | 19 974 | 9 975 | 0 976 | 10 977 | 5 978 | 5 979 | 5 980 | 0 981 | 10 982 | 5 983 | 5 984 | 10 985 | 10 986 | 10 987 | 0 988 | 14 989 | 5 990 | 9 991 | 0 992 | 5 993 | 0 994 | 5 995 | 0 996 | 5 997 | 10 998 | 10 999 | 13 1000 | 5 1001 | -------------------------------------------------------------------------------- /tools/tracefile_parse.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | import json 4 | import argparse 5 | 6 | need_merged_file = True 7 | raw_path = '../dataset/workload/osborn/raw/' 8 | out_path = '../dataset/workload/osborn/' 9 | n_cpu = 8 10 | trace_cpuid_low = 4 11 | trace_cpuid_high = 7 12 | # window_sec = 0.02 # 20ms timer_rate 13 | window_sec = 0.01 # 负载聚合到10ms,以适配10ms,20ms,30ms...的timer_rate 14 | quantum_sec = 0.001 # 解析序列的最小时间单位,我们不在意事件在1.2ms还是1.4ms发生的,1ms 15 | frame_sec = 0.016 # 1帧的时长,16.7ms归到16ms 16 | 17 | merged_load_seq = list() 18 | load_shift = 7 19 | load_scale = 100 # 满负载是100 20 | busy_ratio_to_load = lambda busy_ratio: int(round(busy_ratio * load_scale)) 21 | 22 | # 提取cpu c-state信息 23 | r_idle = r'^ {10}<.{20}\[(\d{3})\].{6}(\d+.\d{6}): cpu_idle: state=(\d{1,10}) ' 24 | re_idle = re.compile(r_idle, re.MULTILINE) 25 | 26 | def parse_cstate(systrace, start_time_sec): 27 | t = re_idle.findall(systrace) 28 | idle_trace = [(int(cpuid), float(time), int(state)) for cpuid, time, state in t] 29 | 30 | # https://www.kernel.org/doc/Documentation/trace/events-power.txt 31 | # cpu_idle "state=%lu cpu_id=%lu" 32 | # Note: the value of "-1" or "4294967295" for state means an exit from the current state, 33 | CSTATE_EXIT = 4294967295 34 | # 准备进入cstate的犹豫时间,40us来自/sys/devices/system/cpu/cpu4/cpuidle/state0/latency 35 | WAIT_TO_SEE_SEC = 0.000040 36 | # cstate = 0 -> C1, cstate = 2 -> C3 37 | is_busy = lambda cstate: cstate == CSTATE_EXIT 38 | cstates = [999] * n_cpu 39 | cstates_start = [start_time_sec] * n_cpu 40 | busy_durations = [0.0] * n_cpu 41 | busy_seq = [] 42 | window_start = start_time_sec 43 | 44 | for cpuid, time, state in idle_trace: 45 | # quantum时间截止,回写cpu busy时间 46 | while time - window_start > quantum_sec: 47 | window_start += quantum_sec 48 | for i in range(n_cpu): 49 | if is_busy(cstates[i]): 50 | busy_durations[i] = busy_durations[i] + window_start - cstates_start[i] 51 | cstates_start[i] = window_start 52 | busy_seq.append(tuple(busy_durations)) 53 | for i in range(n_cpu): 54 | busy_durations[i] = 0.0 55 | 56 | if is_busy(cstates[cpuid]): 57 | delta = time - cstates_start[cpuid] - WAIT_TO_SEE_SEC 58 | busy_durations[cpuid] = max(0.0, busy_durations[cpuid] + delta) 59 | cstates[cpuid] = state 60 | cstates_start[cpuid] = time 61 | 62 | # 按照window_sec长度聚集负载 63 | n_quantum = int(window_sec / quantum_sec) 64 | windowed_load_seq = [] 65 | sum_busy = [0.0] * n_cpu 66 | for idx in range(len(busy_seq)): 67 | for cpuid in range(n_cpu): 68 | sum_busy[cpuid] += busy_seq[idx][cpuid] 69 | # 如果在循环结束时有不完整的windowed_load,丢弃 70 | if idx % n_quantum == n_quantum - 1: 71 | windowed_loads = [busy_ratio_to_load(busy / window_sec) for busy in sum_busy] 72 | windowed_load_seq.append(windowed_loads) 73 | sum_busy = [0.0] * n_cpu 74 | 75 | # 传递给interactive调速器的会是集群中负载最大的数字 76 | max_load_seq = [max(loads[trace_cpuid_low: trace_cpuid_high+1]) for loads in windowed_load_seq] 77 | 78 | return max_load_seq, windowed_load_seq, busy_seq 79 | 80 | 81 | # 提取触摸响应,需要quantum时间进行聚集 82 | r_input = r'^.{20,45} (\d{1,10}.\d{6}):.+?\|pokeUserActivity' 83 | re_input = re.compile(r_input, re.MULTILINE) 84 | 85 | def parse_input(systrace, start_time_sec): 86 | t = re_input.findall(systrace) 87 | input_trace = [(float(x) - start_time_sec) for x in t] 88 | ret = set([int(time / window_sec) * window_sec for time in input_trace]) 89 | ret = sorted(list(ret)) 90 | return ret 91 | 92 | 93 | # 提取渲染帧起始时间,ui_thread为帧事件起始时间,按照input事件响应的app进行跟踪 94 | # 后台不交互的也会有ui渲染线程在活动,频率甚至可以很高(16ms),我们只关注前台用户正在使用的进程 95 | r_ui_thread = r'^.{20,45} (\d{1,10}.\d{6}).{23}\|(\d{3,6})\|Choreographer#doFrame' 96 | re_ui_thread = re.compile(r_ui_thread, re.MULTILINE) 97 | r_input_ui = r'^.{20,45} (\d{1,10}.\d{6}).{23}\|(\d{3,6})\|deliverInputEvent' 98 | re_input_ui = re.compile(r_input_ui, re.MULTILINE) 99 | 100 | def parse_render(systrace, start_time_sec): 101 | t = re_ui_thread.findall(systrace) 102 | ui_trace = [(float(time) - start_time_sec, int(pid)) for time, pid in t] 103 | t = re_input_ui.findall(systrace) 104 | ui_input_trace = [(float(time) - start_time_sec, int(pid)) for time, pid in t] 105 | 106 | # 提取当前交互在哪个进程发生,记录开始时间和进程PID 107 | input_log = [] 108 | if len(ui_input_trace) > 0: 109 | input_log.append((0.0, ui_input_trace[0][1])) 110 | for time, pid in ui_input_trace: 111 | t = time - input_log[-1][0] 112 | # 至少等待16ms再切换当前交互的进程 113 | if not pid == input_log[-1][1] and t > frame_sec: 114 | input_log.append((time, pid)) 115 | input_log.append((999999, 0)) 116 | 117 | # 提取帧渲染开始的时间,用于辅助流畅度评分 118 | ret = [] 119 | idx_input_log = 0 120 | prev_time = 0.0 121 | for time, pid in ui_trace: 122 | # 按照之前的结果,跳过并非前台交互程序的UI起始标志 123 | if input_log: 124 | if time > input_log[idx_input_log + 1][0]: 125 | idx_input_log += 1 126 | if not pid == input_log[idx_input_log][1]: 127 | continue 128 | delta = time - prev_time 129 | # 避免帧渲染请求太过重叠,进行没必要的卡顿评测 130 | # 跳过断断续续渲染请求的第一帧,通常这个负载相比之前的变化很大,不算在卡顿评测内 131 | if delta > 0.6 * frame_sec and delta < 5 * frame_sec: 132 | ret.append(int(round(time / quantum_sec)) * quantum_sec) 133 | prev_time = time 134 | return ret 135 | 136 | 137 | # 按照DOM标签提取原始trace信息 138 | r_tracedata = r'^ ' 139 | re_tracedata = re.compile(r_tracedata, re.MULTILINE | re.DOTALL) 140 | 141 | # 提取起始时间戳 142 | r_starttime = r'^.{42}(\d{1,10}.\d{6}):' 143 | re_starttime = re.compile(r_starttime, re.MULTILINE) 144 | 145 | def parse_trace(input_file): 146 | print('processing', input_file) 147 | trace_datas = None 148 | with open(input_file, 'r') as f: 149 | content = f.read() 150 | trace_datas = re_tracedata.findall(content) 151 | 152 | if not trace_datas: 153 | print('load err') 154 | return 155 | 156 | # trace-data 标签数据块共有3个,第一个是进程信息,第二个是systrace,第三个是录制trace的命令行 157 | systrace = trace_datas[1] 158 | start_time_sec = float(re_starttime.findall(systrace, 0, 2000)[0]) 159 | 160 | # 原始数据预处理 161 | max_load_seq, windowed_load_seq, busy_seq = parse_cstate(systrace, start_time_sec) 162 | input_seq = parse_input(systrace, start_time_sec) 163 | render_seq = parse_render(systrace, start_time_sec) 164 | 165 | # CPU4-7的最大负载,CPU4负载,CPU5负载,CPU6负载,CPU7负载,是否有触摸事件 166 | packed_loads_seq = [] 167 | input_quantum_set = set([int(ftime / quantum_sec) for ftime in input_seq]) 168 | n_window_quantum = int(window_sec / quantum_sec) 169 | time_quantum = 0.0 170 | for max_load, loads in zip(max_load_seq, windowed_load_seq): 171 | has_input_event = int(time_quantum in input_quantum_set) 172 | time_quantum += n_window_quantum 173 | packed_loads = [max_load, ] 174 | packed_loads.extend(loads[trace_cpuid_low: trace_cpuid_high + 1]) 175 | packed_loads.append(has_input_event) 176 | packed_loads_seq.append(packed_loads) 177 | 178 | # 注意:16ms的帧可以横跨三个10ms的窗口 179 | # 帧在第x个ms开始,帧内16ms的在各个核心的负载的最大值 180 | packed_render_loads_seq = [] 181 | len_busy_seq = len(busy_seq) 182 | n_frame_quantum = int(frame_sec / quantum_sec) 183 | for render_start_time in render_seq: 184 | idx_start = int(render_start_time / quantum_sec) 185 | idx_end = idx_start + n_frame_quantum 186 | if idx_end > len_busy_seq: 187 | break 188 | period_sum_busy = [0.0] * n_cpu 189 | for idx_busy in range(idx_start, idx_end): 190 | for cpuid in range(trace_cpuid_low, trace_cpuid_high + 1): 191 | period_sum_busy[cpuid] += busy_seq[idx_busy][cpuid] 192 | period_max_load = busy_ratio_to_load(max(period_sum_busy) / frame_sec) 193 | packed_render_loads_seq.append((idx_start, period_max_load)) 194 | 195 | return packed_loads_seq, packed_render_loads_seq 196 | 197 | 198 | def merge_packed_seq(packed_loads_seq_arr, packed_render_loads_seq_arr): 199 | merged_loads = list() 200 | merged_renders = list() 201 | idx_quantum_base = 0 202 | for packed_loads_seq, packed_render_loads_seq in zip(packed_loads_seq_arr, packed_render_loads_seq_arr): 203 | merged_loads.extend(packed_loads_seq) 204 | merged_renders.extend( [ (idx_start + idx_quantum_base, period_max_load) for idx_start, period_max_load in packed_render_loads_seq] ) 205 | # 由于负载序列生成时,最后不满10ms也就是一个window窗长的负载会被丢弃 206 | # 负载序列在尾部拼接完毕后,根据当前负载序列结束时的quantum(ms)数,来设置下一个渲染需求序列的quantum(ms)的序号偏移 207 | idx_quantum_base += len(packed_loads_seq) * int(window_sec / quantum_sec) 208 | return merged_loads, merged_renders 209 | 210 | def parse_load_set(set_path, out_path, sector_key): 211 | info_filename = 'info.json' 212 | info = None 213 | with open(set_path + info_filename, 'r') as filename: 214 | info = json.load(filename) 215 | sector = info[sector_key] 216 | 217 | if len(sector['loadSeq']): 218 | todos = sector['loadSeq'] 219 | else: 220 | print("ERROR: " + sector_key + ".loadSeq is empty") 221 | exit(-1) 222 | 223 | name_arr = list() 224 | packed_loads_seq_arr = list() 225 | packed_render_loads_seq_arr = list() 226 | 227 | for filename in todos: 228 | packed_loads_seq, packed_render_loads_seq = parse_trace(set_path + filename) 229 | name_arr.append(filename) 230 | packed_loads_seq_arr.append(packed_loads_seq) 231 | packed_render_loads_seq_arr.append(packed_render_loads_seq) 232 | packed_data = { 233 | 'src': [filename,], 234 | 'ver': 1, 235 | 'quantumSec': quantum_sec, 236 | 'windowQuantum': int(window_sec / quantum_sec), 237 | 'frameQuantum': int(frame_sec / quantum_sec), 238 | 'efficiencyA53': 1024, 239 | 'efficiency': info['efficiency'], 240 | 'freq': info['freq'], 241 | 'loadScale': load_scale, 242 | 'coreNum': trace_cpuid_high - trace_cpuid_low + 1, 243 | 'windowedLoadLen': len(packed_loads_seq), 244 | 'windowedLoad': packed_loads_seq, 245 | 'renderLoad': packed_render_loads_seq 246 | } 247 | with open(out_path + filename[:-5] + '.json', 'w') as f: 248 | json.dump(packed_data, f, indent=None, separators=(',', ':')) 249 | 250 | if need_merged_file: 251 | merged_loads, merged_renders = merge_packed_seq(packed_loads_seq_arr, packed_render_loads_seq_arr) 252 | packed_data = { 253 | 'src': name_arr, 254 | 'ver': 1, 255 | 'quantumSec': quantum_sec, 256 | 'windowQuantum': int(window_sec / quantum_sec), 257 | 'frameQuantum': int(frame_sec / quantum_sec), 258 | 'efficiencyA53': 1024, 259 | 'efficiency': info['efficiency'], 260 | 'freq': info['freq'], 261 | 'loadScale': load_scale, 262 | 'coreNum': trace_cpuid_high - trace_cpuid_low + 1, 263 | 'windowedLoadLen': len(merged_loads), 264 | 'windowedLoad': merged_loads, 265 | 'renderLoad': merged_renders 266 | } 267 | with open(out_path + sector_key + '-merged' + '.json', 'w') as f: 268 | json.dump(packed_data, f, indent=None, separators=(',', ':')) 269 | return 270 | 271 | 272 | # todos = [ 273 | # # raw_path + 'bili-danmu.html', 274 | # 'gflops.html', 275 | # # 'trace.html' 276 | # ] 277 | 278 | parse_load_set(raw_path, out_path, "onscreen") 279 | parse_load_set(raw_path, out_path, "offscreen") 280 | # parse_trace(todos[0]) 281 | --------------------------------------------------------------------------------