知识总结


  • Home

  • Tags

  • Categories

  • Archives

爬虫介绍

Posted on 2018-10-07 | In spider

“大数据时代” 数据获取方式

  1. 企业生产的用户数据
    腾讯指数 百度指数 阿里指数 微博指数

  2. 数据管理咨询公司
    艾瑞咨询 麦肯锡

  3. 政府/机构提供的公开数据
    国家数据 纳斯达克股票数据

  4. 第三方数据平台购买数据
    数据堂 贵阳大数据交易所

  5. 爬虫爬取数据

爬虫介绍

爬虫按照场景分为两种,通用爬虫和聚焦爬虫

通用爬虫


通用爬虫即搜索引擎用的爬虫系统,如百度,谷歌

1.尽可能把互联网上所有的网页下载下来,放到本地服务器里形成备份,再对这些网页做相关的处理(提取关键字,去掉广告),最后提供一个用户检索的窗口;

2.抓取流程

首先选取一部分已有的URL,把这些URL放到爬取队列;

从队列里取出这些URL,然后解析DNS得到主机IP;然后去这个IP对应的服务器里下载HTML页面,保存到搜索引擎对应的数据;之后把这个爬过的URL放入已爬取队列。

分析网页内容,找出网页里其他的URL连接,继续执行第二步,直到爬取条件结束;

3.搜索引擎如何获取一个新网站的URL

1.主动向搜索引擎提交网址: [百度搜索资源平台](https://ziyuan.baidu.com/)


2.在其他网站里设置外链


3.搜索引擎会和DNS服务商进行合作,可以快速收录新的网站

4.通用爬虫并不是万物皆可爬,它也需要遵守规则:

Robots协议: 协议会指明通用爬虫可以爬取网页的权限

Robots.txt 只是一个建议,并不是所有爬虫都遵守,一般只有大型的搜索引擎爬虫才会遵守,个人爬虫可以不管;

5.通用爬虫工作流程: 爬去网页 –> 存储数据 –>内容处理–>提供检索/排名服务
6.收索引擎排名

1.PageRank(流量越高,越值钱)

2.竞价排名,谁给钱多,谁排名就高

7.通用爬虫的缺点:

  • 只能提供文本信息,但不能提供多媒体文件(音乐,视频)

  • 提供的结果千篇一律,不能针对不同背景领域的人提供不同的搜索结果

  • 不能理解人类语义

聚焦爬虫


聚焦爬虫指的就是程序员写的针对某些内容的爬虫

网页三大特征

  1. 每个网页都有自己的URL(同一资源定位符)来进行定位

  2. 网页都是用HTML(超文本标记语言)来描述页面信息

  3. 网页都使用HTTP/HTTPS(超文本传输协议)来传输HTML数据

爬虫的思路

  1. 首先确定爬取的网页URL地址
  2. 通过HTTP/HTTP协议来获取对应的HTML页面
  3. 提取HTML页面有用的数据,如果是页面的其他URL,那就继续执行第二步

常见步骤:

- HTTP请求的处理,urllib,urllib2,requests,处理后的请求可以模拟浏览器请求,获取服务器响应的文件

- 通过动态页面采集: Selenium+PhantomJS(无界面):模拟真实浏览器加载js,ajax等非静态页面数据    

- Tesseract: 机器学习库,机器图像识别系统,可以处理简单验证码,复杂的验证码可以通过手动输入
- 保存数据     re,xpath,BeautifulSoup4(bs4),jsonpath,pyquery等 使用某种描述性一样来给我们需要提取的数据定义一个匹配规则,符合这个规则的数据就会被匹配,如果是需要的数据,就保存起来

爬虫框架

Scrapy,Pyspider

高定制性高性能(异步网络框架twisted),所以数据下载熟读非常快,提供了数据下载,数据存储,数据下载,提取规则

分布式策略

scrapy redis,在scrapy的基础上添加了以redis数据库为核心的一套组件,让scrapy框架支持分布式的功能,主要是Redis里做指纹去重,请求分配,数据临时存储

结语

爬虫 反爬虫 反反爬虫之间的斗争

其实爬虫做到最后,最头疼的不是负杂的页面,也不是晦涩的数据,而是网站另外一头的运维人员

反爬虫: User Agent,代理,验证码,动态数据加载,加密数据

CPUFreq

Posted on 2018-06-25 | In cpu

代码主要的功能

1) 平台相关的初始化动作,包括CPU core的clock/regulator获取,初始化
2) 生成frequency table,即 CPU core所支持的频率/电压列表。并在初始化的时候将该table保存在policy
3) 定义一个strcut cpufreq_driver变量,填充必要的字段,并根据平台的特性,实现其中的回调函数;
4) 调用cpufreq_register_driver将driver注册到cpufreq framework中
5) cpufreq core会在CPU设备添加时,调用driver的init接口。driver需要在接口中初始化struct cpufreq变量
6) 系统运行过程中,cpufreq core会根据实际情况,调用driver的sepolicy或者target/target_index等接口,设置
CPU的调频策略或者频率值
7) 系统suspend的时候,会将CPU的频率设置为指定的值,或者调用driver的suspend回调函数;系统resume时调用driver的resume回调函数;

cpufreq driver

frequency table是CPU core可以正确运行的一组频率/电压组合

全志TYPE-C使用介绍

Posted on 2018-06-25 | In TYPE-C

有无TYPE-C方案,主从识别和耳机的插拔检测不同;有TYPE-C情况下,主要为TYPE-C逻辑进行侦测;而没有TYPE-C的方案;主从区分需要USB-ID detect管脚进行判断,耳机则靠HP-DET进行区分;

传统侦测方式

主从侦测

usb_id_detect

在没有TYPE-C的硬件上,主要靠USB-ID管脚的上下拉来区分主从;

耳机侦测

耳机结构

3.5mm耳机插头有三段(TRS,Tip-Ring-Sleeve)和四段(TRRS,Tip-Ring-Sleeve)之分,其中三段的不带麦克风,尾段(Sleeve)是公共地;中间环(Ring)是右声道,尖部(Tip)是左声道,四节的分两种,一种是CTIA,一种是OMTP;

耳机结构

HP-L耳机左声道,HP-R耳机右声道,GND接地,V-Mic语音麦克风

耳机座以及传统耳机侦测介绍

耳机座分为支持欧标设计的耳机座和支持美标的耳机座。另外从耳机座左声道的检测方式来又可以分为”Normal-closed type”(常闭型)和“Normal -type”(常开型)两种。设计图如下:

耳机座子

. 在常闭型中,不接耳机时,耳机座左声道和检测端HS-DET接触,接入耳机时,HS-DET与HPH-L不导通

. 在常开型中,不接耳机时,耳机座左声道和检测端HS-DET不接触,插入耳机时,HS-DET与HPH-L导通

耳机侦测电路

如图为常开型结构,HP-DET上拉,当插入耳机后HP-DET和HP-OUTL导通,DET下拉引起软件中断。软件上通过debounce后,检测到持续的低电平,于是认为耳机插入;这时候需要判断,插入的还是三段还是四段,平台上打开mic_bias,当插入的是三段耳机,MIC被拉低,于是判断为三段耳机;若为四段耳机,MIC接近于MIC_BIAS,软件判断该处的直流电压为四段耳机;当按键按下时,MIC的电压发生变化,触发了系统中断,之后软件通过采样该处的电压值确定按下了哪一个按键;

TYPE-C方案侦测方式讲解

TYPE-C主要电路如下

TYPE-C关键电路

Type-C连接并没有在物理结构上区分DFP(Host)和UFP(Device),无连接时DFP未给VBUS供电,连接后通过CC信号线配置,确认连接有效,VBUS供电打开并确认使用哪一个端口传输数据;
状态说明

cc_logic

如图所示

DFP的CC1/CC2会接上拉电阻Rp或电流源,UFP的CC1/CC2会接下拉电阻Rd,AUDIO设备则会接两个下拉电阻

如何确认当前TYPE_C接入设备类型:

echo 1 > /sys/class/axp/axp_num
echo 0x37 > /sys/class/axp_reg && cat /sys/class/axp/axp_reg

若读出状态为ATTACH_SNK 说明接入的是适配器或pc
若读出的状态为ATTACH_SOURCE 说明此时作为host
如读出为AUDIO_ACSY,说明此时为音频设备

type_c_detect

TS5USBA224RSWR:

用于将D-,D+在(USB0-DM,USB0-DP),(HPOUTL,HPOUTR)两种模式之间切换;由于VBUS默认低后,无法满足通过SEL切换状态,故VBUS一般设置为高;通过ASEL来设置高低实现切换

TS3A226AE:

可以用于区分三四节耳机,并且可以将MIC和GROUND区分出来,降低软件设计复杂度;

使用TYPE-C方案时,TYPE-C 中断服务程序负责将D-,D+选择为USB模式的Dp,Dm或者为耳机模式HP-OUTL,HP-OUTR;并通知音频驱动耳机接入;

软件流程为:

一:bmu驱动产生中断:

irqreturn_t axp_tc_in_isr(int irq, void *data)
{
    struct axp_charger_dev *chg_dev = data;
    #ifdef CONFIG_TYPE_C_AUDIO
    struct axp_usb_info *usb = chg_dev->spy_info->usb;
    u8 cc_mode = 0; 
    /*axp_usbac_in(chg_dev);*/
    cc_mode = usb->get_cc_mode(chg_dev); //获取cc 侦测结果
    if (cc_mode == AUDIO_ACSY) {    //如果为音频设备
            usb->set_sel_mode(chg_dev, 1);  //D+ D- 连接到耳机的左右声道
            call_notifier_call_chain(1);    //通知耳机驱动耳机接入
    } else {
            usb->set_sel_mode(chg_dev, 0); //D+ D- 连接到 USB的 Dp,Dm口
            call_notifier_call_chain(0);   //通知耳机驱动拔出
    }    
    #endif
    axp_change(chg_dev);
    return IRQ_HANDLED;
}

二:耳机接受到通知:

static int type_c_chain_notify(struct notifier_block *nb, unsigned long mode, void *_unused)
{
    struct mc_private *ctx = container_of(nb, struct mc_private, type_c_chain_nb);

    if (mode) {
            ctx->detect_state = PLUG_IN; //切换接入状态
            printk("%s PLUG_IN", __func__);
    } else {
            ctx->detect_state = PLUG_OUT;
            printk("%s PLUG_OUT", __func__);
    }

    schedule_delayed_work(&ctx->hs_detect_work,
                            msecs_to_jiffies(10)); //执行音频相关的处理函数
    return 0;
}

软件配置demo

使能TYPE-C SINK与SOURCE 检测功能:

一:sys_config.fex中:

usb_id_gpio = "axp_ctrl"

二:deconfig中

CONFIG_TYPE_C=y

使能TYPE-C耳机功能

一:如原理图所示,使用的是PH10作为选通管脚,故对pmu_typc_c_sel进行配置

[charger0]
 compatible                 = "bmu1760-charger"
pmu_type_c_sel             = port:PH10<1><default><default><0>
 pmu_chg_ic_temp            = 0
pmu_battery_rdc            = 100
 pmu_battery_cap            = 4200

二:deconfig中

CONFIG_TYPE_C_AUDIO=y

进程初识

Posted on 2018-06-25 | In 进程

一:进程结构体

1
声明目录:include/linux/sched.h

进程的状态

1
2
3
4
5
6
volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ 
//1. R:运行(正在运行或在运行队列中等待)
//2. S:中断(休眠中,受阻,在等待某个条件形成或接受到信号)
//3. D:不可中断(收到信号不唤醒和不可运行,进程必须等待直到有中断发生):
//4. T:僵死(进程已终止,但进程描述符存在,直到父进程调用wait4()系统调用后释放)
//5. Z:停止(进程收到SIGSTOP,STGSTP,SIGIN,SIGOU信号后停止运行)

进程的生命周期

进程的进程标识

1
2
pid_t pid;
pid_t tgid;

在linux系统中,所有进程都有直接或间接的联系,每个进程都有其父进程
linux把不同的pid与系统中的每个进程或轻量级线程关联,一个线程组所有线程与零头线程具有相同的pid,存入tgid中;

进程标记

1
unsigned int flags;

反应进程状态信息,但不是运行状态,用于内核识别进程当前的状态,以备下一步操作

表示进程亲属关系的成员

1
2
3
4
5
6
7
8
9
10
11
12
13
/*  
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->real_parent->pid)
*/
struct task_struct __rcu *real_parent; /* real parent process */
struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
/*
* children/sibling forms the list of my natural children
*/
struct list_head children; /* list of my children */
struct list_head sibling; /* linkage in my parent's children list */
struct task_struct *group_leader; /* threadgroup leader */

进程内核栈

1
2
struct thread_info thread_info;
void *stack;

ptrace系统调用

提供一种父进程可以控制子进程运行,并可以检查和改变它的核心image;

优先级

1
2
3
4
int prio,保存静态优先级,可以通过nice系统调用来进行修改
rt_prority,用于保存实时优先级
normal_prio 取决于静态优先级和调度策略
prio 用于保存动态优先级

调度策略相关字段

1
2
policy 调度策略
sched_class 调度类

task_struct的初始化

1
2
3
4
__mmap_switched_data  arch/arm/kernel/head-common.S
-->__mmap_switched_data
-->.long init_thread_union + THREAD_START_SP @ sp
--> INIT_THREAD_INFO(init_task) init/init_task

`

init进程

linux下有3个特殊的进程,idle进程(PID=0),init进程(PID=1)和kthreadd(PID=2)
ilde进程由系统自动创建,运行在内核态
idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_thread产生的进程。完成加载系统后,演变成为进程调度,交换;
init进程由idle通过kernel_thread创建,在内核空间中完成初始化后,加载init程序;

三:僵尸进程

其他

当一个进程在执行时,CPU的所有寄存器中的值,进程的状态以及堆栈中的内容被称为该进程中的上下文。当内核需要切换到另外一个进程时,它需要保存当前的所有状态,即保存当前进程的上下文;以便在再次执行该进程时,能够必得到切换时的状态执行下去。在linux中,当前进程上下文均保存在任务数据结构中;
当发生中断时,内核就在被中断的上下文中,在内核态下执行中断服务历程。但同时会保留所有需要用到的资源,以便中继服务结束时能恢复被中断进程的执行;

进程优先级

设置SCHED_FIFO和50 RT优先级

#chrt -f -a -p 50 10576
设置nice

#renice -n -5 -g 9394

#nice -n 5 ./a.out

参考资料

linux调度器发展简述
linux进程描述符task_struct结构体详解–linux进程的管理与调度(一)
Linux下0号进程的前世(init_task进程)今生(idle进程)—-Linux进程的管理与调度(五)

CPU概述

Posted on 2018-06-25 | In cpu

cpu topology

1.1. cpu拓扑

cluster(socket)->core->Threads(目前为止arm没有提出多线程的概念)
cpu拓扑图

1.2 多核技术

基于制程,扩充性等考虑,芯片厂商会把多个core封装在一个chip上,称为socket。socket的概念在X86架构上使用尤其多,可以理解为插槽;
假设一个插槽上有两个core,那么我在主板上插2个插槽,就是4核系统,插上4个插槽就是8核;arm的话则是另外一个概念cluster,簇
在X86架构的PC上,唯一目的的话是提高CPU的处理性能(不在乎功耗),但在移动市场中(大多是arm),性能提高后,对应着就更多的power消耗;对于设备电源管理以及散热提出了更高的要求。与此同时电池并没有随着CPU的拓扑的进化而进化,于是HMP技术就被提出来了;

1.3HMP(Heterogeneous Multi-Processing)

big-little:

  • 在一个chip中封装两类ARM Core,以kirin 960为例:一类为高性能Core,4核ARM A73,最高主频为2.4G,一类为低性能Core,4核ARM A53,最高主频为1.8G
    cpu拓扑图

DynamIQ:

  • 在单一cluster内可有8个核心,且可由不同架构,时钟的核心组成,提升了运作效率与配置的弹性,如高通的845 4核ARM A75,最高为2.8,4核 ARM A55,最高为1.8G

DynamIQ较big-little好处:

  1. 单cluster可有8核心
  2. cluster可搭配不同架构的CPU
  3. 各cpu可有独立的运作时钟
  4. CPU各自开关休眠互不影响
  5. 依照效能需求弹性运用各核心

以龙舟比喻ARM的DynamIQ与先前的big.LITTLE技术,我们把龙舟当成cluster,船员当成core,那么big.LITTLE龙舟上只能有4个船员,而且每个船员身材需要一样(核心架构),划船的时候若多位船员一起划船时,每个人的出力均等(频率一致),不能有人慢划或者快划;
当使用DynamIQ时,每艘船(cluster)上可以有8位高低胖瘦不等(架构)的船员(core),换船频率可以不等,且船员可以依照指令睡觉(关闭),休息(休眠),或划船(运作);

cpu内核代码框架

  1. 系统启动时,CPU core的初始化,信息获取
  2. 系统启动时,CPU core的启动(enable)
  3. 系统运行过程中,根据当前负荷,动态enable/disable 某些CPU core,以便在性能与功耗间平衡
  4. cpu core的hotplug支持,所谓的hotplug,是可以在系统运行的过程中,动态的增加或者减少CPU core(可以是物理上,也可以是逻辑上)
  5. 系统运行过程中CPU idle管理
  6. 系统运行过程中,根据当前负荷,动态的调整CPU core的电压和频率,以便在性能和功耗之间平衡

cpu拓扑图
arch-depedent部分位于”arch\arm64\kernel”负责平台相关的控制操作,包括

1
2
3
4
cpu 信息的获取(cpuinfo)
cpu拓扑结构的获取(cpu topology)
底层的CPU操作(init,disable等)的实现,cpu ops
SMP相关的初始化(smp)

arch-independent负责实现平台无关的抽象,包括

1
2
3
4
cpu control模块,屏蔽底层平台相关实现细节,提供控制CPU(enable,disable等)的统一API,供系统启动,进程调度等模块调用
cpu subsystem driver像用户空间提供CPU hotplug有关的功能;
cpuidle,处理CPU idle有关的逻辑
cpufreq 处理CPU frequency调整有关的逻辑

cpu的状态表示

  1. possible CPU: 就是在DTS中指定了的,物理存在的CPU core
1
2
3
start_kernel->boot_cpu_init->smp_process_id用于获取cpu id
->set_cpu_xxx,用于将指定的CPU设置为(或清除)指定状态
->setup_arch->smp_init_cpus->sunxi_smp_init_cpus->set_cpu_possible(i, true)
  1. present cpu: 被kernel标识的,具备执行代码条件,后续可以在需要的时候(如hotplug的时候),启动该CPU
1
2
3
4
start_kernel->rest_init->kernel_init->kernel_init_freeable
->smp_prepare_cpus
if (cpu_prepare(cpu)) /**/
set_cpu_present(cpu,true);
  1. online CPU: 某个CPU是present的,不一定是boot,所谓CPU boot,就是让CPU执行(取指译码/执行)代码
  2. active CPU 只是为了方便调度器操作

参考资料

一图看懂ARM DynamIQ运作原理
Linux CPU core的电源管理(1)概述

Thermal 框架梳理

Posted on 2018-06-25 | In thermal

theraml框架框图

  1. thermal_zone_device:获取温度设备的抽象
  2. thermal_cooling_device: 降低温度措施的抽象
  3. thermal_governor:温控策略,step wise, bangbang,user space,power_allocator,fair_share
  4. thermal_core : 作为user space和kernel的接口,同时也是Thermal框架的中枢

相关的节点:/sys/class/thermal
thermal

thermal_zone_device

dts
    cpu_thermal_zone{

                            polling-delay-passive = <1000>;
                            polling-delay = <2000>;
                            thermal-sensors = <&ths_combine0 0>;

                            trips{
                                    cpu_trip0:t0{
                                            temperature = <65>;
                                            type = "passive";
                                            hysteresis = <0>; 
                                    };   
                                    cpu_trip1:t1{
                                            temperature = <75>;
                                            type = "passive";
                                            hysteresis = <0>; 
                                    };   
    ....

struct thermal_zone_of_device_ops {
    int (*get_temp)(void *, int *);  
    int (*get_trend)(void *, int, enum thermal_trend *); 
    int (*set_trips)(void *, int, int); // 设置温度窗口,当温度超过设置点需要通过thermal_zone_device_update
    int (*set_emul_temp)(void *, int);
    int (*set_trip_temp)(void *, int, int);
};

struct thermal_zone_of_device_ops combine_ops = { 
    .get_temp          = sunxi_combine_get_temp,
    .set_emul_temp     = sunxi_combine_set_emul_temp,

};

在probe中完成注册:
sensor->tz = thermal_zone_of_sensor_register(&pdev->dev,
        id, sensor, &combine_ops);

温度获取流程

sunxi_combine_get_temp //sunxi_ths_combine.c
    -->ret = controller->ops->get_temp(controller,sensor_id, &temp);
sunxi_ths_get_temp  // sunxi_ths_core.c
    -->t = ths_driver_get_temp(ths_data, id);
ths_driver_reg_to_temp(reg_data, id, ths_data->ths_driver_version, ths_data->ths_coefficent->calcular_para); //sunxi_ths_driver.c

thermal_core

在thermar core作为中枢注册governor,注册Thermal类,并且基于Device Tree注册Thermal Zone;提供Thermal zone注册函数,Cooling Device注册函数,提供将Cooling设备绑定到Zone的函数,一个Thermal Zone可以有多个Cooling设备;同时还提供一个核心函数Thermal_\zone_device\update作为Thermal中断处理函数和轮询函数,轮询时间会根据不同Trip Delay调节

1.thermal_init

thermal_init

2.netlink

netlink是linux提供的用于内核和用户态进程之间通信的方式。一般来说用户空间和内核空间的通信方式有三种:/proc,ioctl,netlink,而前两种是单向的,但是netlink可以实现双工通信;虽然netlink主要用于用户空间和内核空间的通信,但是也能用于用户空间的两个进程通信。只是进程间通信有其他很多方式,除非需要用到netlink的广播特性;

netlink有以下特点:

1.支持全双工,异步通信(当然也同步也支持)

2.用户空间可使用标准的BSD socket接口

3.在内核空间使用专门的内核API接口

4.支持多播(因此支持”总线”式通信,可实现消息订阅)

5.在内核端可用于进程上下文和中断上下文;

用户态使用netlink:

用户态应使用标准的socket APIs,socket(),bind(),sendmsg(),recvmsg()和close()就可以使用netlink socket

netlink内核API

一:定义协议类型 (可省略)

二:netlink_kernel_create

三:设置目标地址与源地址

四:通过netlink_unicast和netlink_broadcast发送消息;

3.thermal轮询流程

在thermal core中通过不断的轮询来检测温度变化,如果温度没有达到crital则调用governor的throttle,通过governor的throttle决定下一次轮询的时间;如果温度为crital则走关机流程;

thermal_core调用流程

cooling_device

嵌入式设备通过改变频率电压,来达到改变功耗的目的,cooling_device提供了获取当前设备的温控状态以及设置等接口;
cooling_device

thermal_cooling_device

dts:
cooling-maps{
                                    bind0{
                                            contribution = <0>;
                                            trip = <&cpu_trip0>;
                                            cooling-device
                                            = <&cpu_budget_cooling 1 1>;
                                    };
                                    bind1{
                                            contribution = <0>;
                                            trip = <&cpu_trip1>;
                                            cooling-device
                                            = <&cpu_budget_cooling 2 2>;
                                    };
...
               cpu_budget_cooling:cpu_budget_cool{
                    compatible = "allwinner,budget_cooling";
                    device_type = "cpu_budget_cooling";
                    #cooling-cells = <2>;
                    status = "okay";
                    state_cnt = <7>;
                    cluster_num = <1>;
                    state0 = <1800000 4>;
                    state1 = <1512000 4>;
                    state2 = <1416000 4>;
                    state3 = <1200000 4>;
                    state4 = <1008000 3>;
                    state5 = <1008000 2>;
                    state6 = <1008000 1>;
            };
...


struct thermal_cooling_device_ops {
    int (*get_max_state) (struct thermal_cooling_device *, unsigned long *);   //获取最高的cooling状态的回调函数,指最低功耗的OPP                       
    int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *); //获取当前cooling状态的回调函数                          
    int (*set_cur_state) (struct thermal_cooling_device *, unsigned long);   //根据cooling_state执行cpufreq的回调函数,是执行的实体                         
    int (*get_requested_power)(struct thermal_cooling_device *,
                               struct thermal_zone_device *, u32 *);//获取当前当前CPU的功耗值,包括dynamic功耗和static功耗。中间需要用到dyn_power_table进行转换                                  
    int (*state2power)(struct thermal_cooling_device *,
                       struct thermal_zone_device *, unsigned long, u32 *); //将CPU cooling状态转换成需要消耗的功耗值;                          
    int (*power2state)(struct thermal_cooling_device *,
                       struct thermal_zone_device *, u32, unsigned long *);//将CPU所能获取的最大功耗值转换成cooling状态                           
};

static struct thermal_cooling_device_ops const sunxi_cpu_cooling_ops = {
    .get_max_state = cpu_budget_get_max_state,
    .get_cur_state = cpu_budget_get_cur_state,
    .set_cur_state = cpu_budget_set_cur_state,
};
cool_dev = thermal_of_cooling_device_register(
                        pdev->dev.of_node,
                        SUNXI_BUDGET_COOLING_NAME,
                        budget_cdev,
                        &sunxi_cpu_cooling_ops);

set_cur_state
    ->cpu_budget_apply_cooling(cooling_device, state); 
        ->sunxi_hotplug_update_state(cooling_device, cluster);
            ->autohotplug_roomage_limit(cluster, min, max); //限制最大的核数
        ->sunxi_cpufreq_update_state(cooling_device, cluster);  ??怎么传递这个参数的
            ->cpufreq_update_policy(cpuid); //限制最大频率

thermal governor

内核中的governor策略

step wise: Open loop control. Temperature threshold and trend based. Walk through each cooling device cooling state, step by step.

fair share: Weight based. Determine the cooling device state based on assigned weight partitioning.

bang bang: uses a hysteresis to switch abruptly on or off a cooling device. It is intended to control fans, which can not be throttled but just switched on or off.

power allocator: Closed loop control. Based on power budget, temperature, and current power consumption of each involved device.

user space: hand off the control of a thermal zone to user space. Example: thermald and iTux.

手机端的thermal配置情况

mtk

以魅族 15plus为例

15Plus:/sys/class/thermal $ ls
cooling_device0 cooling_device2 cooling_device4 cooling_device6 thermal_zone1 thermal_zone3 thermal_zone5\
cooling_device1 cooling_device3 cooling_device5 thermal_zone0   thermal_zone2 thermal_zone4

cooling device

15Plus:/sys/class/thermal/cooling_device1 $ ls
cur_state max_state power subsystem type uevent
for i in $(seq 0 6)
do
    printf "cooling_device$i\t"
    type=$(cat cooling_device$i/type)
    printf "$type\t"
    cur_state=$(cat cooling_device$i/cur_state)
    printf "$cur_state\t"
    max_state=$(cat cooling_device$i/max_state)
    printf "$max_state\n"
done
cooling_device0         battery_control02       0       1
cooling_device1         battery_control01       0       1
cooling_device2         battery_control00       0       1
cooling_device3         thermal-cpufreq-0       0       13
cooling_device4         thermal-cpufreq-1       0       8
cooling_device5         thermal-gpufreq-0       0       4
cooling_device6         thermal-isp-0           0       2

thermal_zone

for i in $(seq 0 5)
do
    printf "thermal_zone$i\t"
    type=$(cat thermal_zone$i/type)
    printf "$type\t"
    policy=$(cat thermal_zone$i/policy)
    printf "$policy\n"
done

thermal_zone0   mngs-thermal    power_allocator        cdev【0-1】 -> ../cooling_device3        thermal-cpufreq-0
thermal_zone1   APOLLO          step_wise            cdev【0-4】 -> ../cooling_device4        thermal-cpufreq-1
thermal_zone2   GPU             power_allocator     cdev【0-1】 -> ../cooling_device5        thermal-gpufreq-0
thermal_zone3   ISP             step_wise             cdev【0-4】 -> ../cooling_device6        thermal-isp-0
thermal_zone4   battery         step_wise
thermal_zone5   meizu_ntc       step_wise             cdev【0-2】 -> ../cooling_device【0-2】    battery_control0【0-2】

海思

以荣耀9为例

cooling_device

cooling_device0 thermal-devfreq-0       05
cooling_device1 thermal-cpufreq-0       04
cooling_device2 thermal-cpufreq-1       04

thermal_zone

thermal_zone0   soc_thermal     power_allocator  cdev【0-2】 -> ../cooling_device[0-2]
thermal_zone1   Battery         user_space
thermal_zone2   cluster0        user_space    
thermal_zone3   cluster1        user_space
thermal_zone4   gpu                user_space
thermal_zone5   modem           user_space
thermal_zone6   ddr                user_space
thermal_zone7   system_h        user_space
thermal_zone8   flash_led       user_space
thermal_zone9   charger         user_space
thermal_zone10  pa_0            user_space
thermal_zone11  dcxo0           user_space
thermal_zone12  hisi_shell      user_space
thermal_zone13  hisi_ambient    user_space

高通

以pixel为例

cooling_device

                    type                cur_state    max_state
cooling_device0 thermal-cpufreq-0       1900800         21
cooling_device1 thermal-cpufreq-1       2457600            30

thermal_zone

thermal_zone0   mnh_ipu1                step_wise
thermal_zone1   mnh_ipu2                   step_wise
thermal_zone2   mnh_cpu                 step_wise
thermal_zone3   mnh_lpddr                   step_wise
thermal_zone4   usb                     step_wise
thermal_zone5   battery                 step_wise
thermal_zone6   usb_port_temp           step_wise
thermal_zone7   pm8998_tz               step_wise
thermal_zone8   pmi8998_tz              step_wise
thermal_zone9   pm8005_tz               step_wise
thermal_zone10  msm_therm                   step_wise
thermal_zone11  quiet_therm             step_wise
thermal_zone12  xo_therm                step_wise
thermal_zone13  fpc_therm               step_wise
thermal_zone14  back_therm              step_wise
thermal_zone15  pa_therm                step_wise
thermal_zone16  tsens_tz_sensor0        step_wise
thermal_zone17  tsens_tz_sensor1        step_wise
thermal_zone18  tsens_tz_sensor2        step_wise
thermal_zone19  tsens_tz_sensor3        step_wise
thermal_zone20  tsens_tz_sensor4        step_wise
thermal_zone21  tsens_tz_sensor7        step_wise
thermal_zone22  tsens_tz_sensor8        step_wise
thermal_zone23  tsens_tz_sensor9        step_wise
thermal_zone24  tsens_tz_sensor10       step_wise
thermal_zone25  tsens_tz_sensor11       step_wise
thermal_zone26  tsens_tz_sensor12       step_wise
thermal_zone27  tsens_tz_sensor13       step_wise
thermal_zone28  tsens_tz_sensor14       step_wise
thermal_zone29  tsens_tz_sensor15       step_wise
thermal_zone30  tsens_tz_sensor16       step_wise
thermal_zone31  tsens_tz_sensor17       step_wise
thermal_zone32  tsens_tz_sensor18       step_wise
thermal_zone33  tsens_tz_sensor19       step_wise
thermal_zone34  tsens_tz_sensor20       step_wise
thermal_zone35  tsens_tz_sensor21       step_wise
thermal_zone36  limits_sensor-00        step_wise
thermal_zone37  limits_sensor-01        step_wise
thermal_zone38  bcm15602_tz             step_wise
thermal_zone39  bms                     step_wise
thermal_zone40  GLM_soc                 step_wise

通过观察发现,power allocator,step wise,user space为常用的governor,故以下简单介绍此三种thermal;

Power allocator

IPA的发展历史

在2013,ARM 开始在Linux OS中布局IPA,只是介绍了相关的概念和在实际场景中的好处;
在2015年3月3号,第一个完整的IPA提交被纳入Linux,并被merge到linux4.2.所以linux4.2之后不用再打相关的pactch

在讲power allocator 前,需要先讲个概念PID(Proportional Integral Derivative)的概念;

PID控制器

pid

PID控制器是一个闭环的系统,通过将输出反馈到输入,这使系统可以得到更精细和自适应的控制

.u(t) is the control signal.

.y(t)is the actual output value.

.r(t) is the reference value, also called the setpoint. It is the desired output value.

.e(t) is the control error (e(t) = r(t) − y(t)). It shows the difference between the reference value and the actual output value.

.The term Plant refers to the object that is being controlled
The control signal 𝑢(𝑡) is a sum of the following terms:

The P-term: This term is proportional to the error. It acts on the present value of the error.
The I-term: This term is proportional to the integral of the error. It represents the accumulation of past errors.
The D-term: This term is proportional to the derivative of the error. It can be interpreted as a prediction of future errors, based on linear extrapolation according to the current rate of change.

PID控制器适用于多个控制领域,除了多路输入输出;

对于thermal 而言,对应的PID如以下模样:

thermal_pid

Pmax 是根据当前的温度和预想的温度计算出来的系统可以运行的最大功耗:

计算公式如下:

P_max = k_p * e + k_i * err_integral + k_d * diff_err + sustainable_power
e = desired_temperature - current_temperature
err_integral is the sum of previous errors
diff_err = e - previous_error

. 所谓的Sustainable Power是在不同OPP情境下,某一个最大的OPP的温度保持基本稳定,比其大者,温度上升明显;比其小者温度保持不变或者下降;这可以通过监测不同OPP对应的温度值,得到一个Sustainable Power

以荣耀9为例: 
Sustainable Power = 4500
trip_point_1_temp = 80000;
trip_point0_temp = 55000;
if (!tz->tzp->k_po || force)
    tz->tzp->k_po = int_to_frac(sustainable_power) / temperature_threshold;
k_po = sustainable_power / (desired_temperature - switch_on_temp) = (4500 * 1024)/(80000-55000) = 184.32
if (!tz->tzp->k_pu || force)
     tz->tzp->k_pu = int_to_frac(2 * sustainable_power) / temperature_threshold 
k_pu = 2 * sustainable_power / (desired_temperature - switch_on_temp) = = (2 * 4500 * 1024)/(80000 - 55000) =  368.64;
tz->tzp->k_i = int_to_frac(10) / 1000 = 10.24;
k_i = 10 * 1024 /1000 = 为积分常数,用来补偿偏移;当温度误差低于 integral_cutoff(一般为0)误差就会被累计
k_d 为求导,一般设置为0

power_allocate_throttle

step wise

根据当前温度的趋势(上升,下降)和与当前的trip温度对比,来决定CPU下一次的cooling状态

step_wise

user space

通过将温度,事件,暴露到上层,上层应用再去驱动throttle进行控温,目前没有相关的资料可以分析,暂时不做分析;

参考资料

Android/Linux Thermal框架分析及其Governor对比

Android/Linux Thermal Governor之IPA分析与使用

LinuxNetlink基本使用

内核启动参数,模块参数与sysfs,sysctl,系统调用和netlink

电脑待机,睡眠,休眠分不清楚?P,T,S,G,C电源状态一次看懂

The thermal framework

intelligent_power_allocation_white_paper

DS5相关介绍

Posted on 2018-06-25 | In 工具使用
  • 一. DS5 与 DSTREAM
    • 1. DS5 是一个软件开发工具
    • 2. DSTREAM 是一个硬件仿真工具
  • 二. 安装DS5
  • 三. DS5的使用
    • 1.新建debug control
    • 2.建立连接
    • 3.load vmlinux
    • 4.查看logbuf
    • 5.load 源码单步调试
  • 四:csat的使用
    • 1.csat:CoreSight Access Tool(CSAT)
    • 2.CSAT & DS-5 diff
    • 3.CSAT的命令

一. DS5 与 DSTREAM

1. DS5 是一个软件开发工具

ds5
从以下工具发展而来:DS5<RVDS<ADS<SDT,目前除DS5外其他都已停用;
有图形化的streamline性能分析器,可基于C源码,汇编程序,地址对bare裸机程序,uboot,kernel,驱动,app进行热点,程序瓶颈,CPU使用,Cache hit/miss,功耗分析

2. DSTREAM 是一个硬件仿真工具

dstream
共有7个接口,其中ARM JTAG 14,TI JTAG 14,ARM JTAG 20和Coresight 10这4个接口仅有debug功能,同时MICTOR 38,MIPI34,Coresight 20这3个接口有debug+trace功能

二. 安装DS5

  1. 安装虚拟网卡;
  2. 安装DS5-19和完成licence注册
  3. 拷贝模型到安装目录下
  4. 打开DS5

三. DS5的使用

1.新建debug control

use1

2.建立连接

use2

3.load vmlinux

当建立连接后一般都是一些汇编语言,这时候需要将vmlinux load进DS5方便debug
load

4.查看logbuf

logbuf的大小由.config中的CONIFG_LOG_BUF_SHIFT决定,在init/Kconfig中有对应的说明
如何确定log_buf的地址:
目前在arm64中log_buf的地址对应的是system.map中__log_buf对应的地址;
load
arm32对应的地址为system.map的log_buf对应地址的地址,需要ds5找到映射位置后在通过此地址去查看log_buf中的内容:
load

5.load 源码单步调试

load

四:csat的使用

1.csat:CoreSight Access Tool(CSAT)

DS-5的命令行工具,处理器挂住了,通过DS-5无法连接上,只能用CSAT连接上,但是CSAT无法访问到处理器内部的寄存器;
一般访问步骤:
读寄存器,如果不ok,说明总线挂了;
读dram,如果dram不ok,说明mbus挂了;
读PC,如果PC读取不ok,说明CPU挂了

2.CSAT & DS-5 diff

CSAT:通过APB总线连接,CPU挂死之后还能连接上,不能访问到CPU内部的寄存器
DS5:通过CPU连接,CPU挂死之后无法连接上,能够访问到CPU内部的寄存器

3.CSAT的命令

  1. 打开DS5的命令行;
  2. 输入以下命令:
1
2
3
4
csat
con USB
chain dev=auto clk=A
dvo 0
command short name Description
dpmemread dmr Read mememory
dpmemwrite dmw Write memory
dpfileload dfl Load a file into memory
dpfilesave dfs Save a block of memory to file.

example:

1
2
3
4
5
dmr 0 0x00010000 0x50
#save a block of memory to file
dfs 0 0x047fb000 0x350 dram2.bin
#load a file into memory
dfl 0 bin 0x8000 myfile.bin Load binary file into 0x8000 on AP 0

程序的内存空间

Posted on 2018-06-19 | In 内存管理

一:内核空间和用户空间

Linux的虚拟地址空间范围是0~4G,linux内核将这4G空间分为两部分,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF)供内核使用,称为“内核空间”。而将较低的3G字节(从虚拟地址0X00000000到0xBFFFFFFFF)供各个进程使用,称为“用户空间”。因为每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间
每个进程的用户空间都是完全独立,互不相干,用户进程各自有不同的页表。而内核空间是有内核负责映射的,不随进程改变,是固定的。内核空间有自己对应的页表;
这里指的32位内核地址空间划分,64位内核地址空间是不同的
进程空间分布

1.1:内核空间

linux内核在启动的时候会打印出内核空间的布局图:
init/mian.c:
start_kernel->mm_init->mem_init

1
2
3
4
5
6
7
8
9
10
11
12
13
Memory: 996228K/1048576K available (9216K kernel code, 1381K rwdata, 2940K rodata, 1024K init, 397K bss, 44156K reserved, 8192K cma-reserved, 253952K highmem)
[ 0.000000] Virtual kernel memory layout:
[ 0.000000] vector : 0xffff0000 - 0xffff1000 ( 4 kB)
[ 0.000000] fixmap : 0xffc00000 - 0xfff00000 (3072 kB)
[ 0.000000] vmalloc : 0xf0800000 - 0xff800000 ( 240 MB)
[ 0.000000] lowmem : 0xc0000000 - 0xf0000000 ( 768 MB)
[ 0.000000] pkmap : 0xbfe00000 - 0xc0000000 ( 2 MB)
[ 0.000000] modules : 0xbf000000 - 0xbfe00000 ( 14 MB)
[ 0.000000] .text : 0xc0008000 - 0xc0a00000 (10208 kB) //代码段
[ 0.000000] .init : 0xc0e00000 - 0xc0f00000 (1024 kB) //init段 包含了大部分模块的初始化数据
[ 0.000000] .data : 0xc0f00000 - 0xc1059518 (1382 kB) //数据段的起始和结束地址,保存大部分内核的变量
[ 0.000000] .bss : 0xc105b000 - 0xc10be54c ( 398 kB) //BSS段的开始和结束地址,包含初始化为0的所有静态全局变量
[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1

内核空间

内核空间分为三部分:ZONE_DMA(16M),ZONE_NORMAL(16~896),ZONE_HIGMEM(896~1G),高端内存
内核地址空间分为物理内存映射区,虚拟内存分配区,高端页面映射区,专用页面映射区保留区
内核空间中存放的是内核代码和数据,而进程的用户空间中存放的是用户程序的代码和数据。不管是内核空间还是用户空间,它们都处于虚拟空间中,虽然内核空间占据了每个虚拟空间的最高1GB字节,但映射到物理内存却总是从最低(0X00000000),另外,使用虚拟地址可以很好的保护内核空间不被破坏,虚拟地址到物理地址转换过程中有操作系统和CPU共同完成
内核空间是持续存在的,并且在所有进程中都映射到同样的物理内存,内核代码和数据总是可寻址的,随时准备处理中断和系统调用。

1.2:用户空间分布

程序段(Text):程序代码在内存中的映射,存放函数体的二进制代码。
初始化过的数据(Data):在程序运行初已经对变量进行初始化的数据
未初始化过的数据(BSS):在程序运行初未对变量进行初始化的数据
栈(Stack):存储局部,临时变量,函数调用时,存储函数的返回指针,用于控制函数的调用和返回。在程序块开始时自动分配内存,结束时自动释放内存,其操作方式类似于结构中的栈;
堆(Heap):存储动态内存分配,需要程序员手工分配,手工释放;

三:内存溢出,内存泄漏,内存越界,缓存区溢出,栈溢出

内存溢出:要求分配的内存超出了系统能给予的
内存越界:申请了一块内存,在使用这块的时候,超出了你申请的范围
缓冲区溢出:当计算机向缓冲区填充区内填充数据位数

参考资料:
linux用户空间与内核空间——高端内存详解
ARM架构内核启动分析-head.S(1.1).vmlinux.lds链接脚本分析

内存管理(二)mtp拷贝流程

Posted on 2018-06-17 | In 内存管理

背景知识介绍

android 从3.0开始集成MTP功能,主要原因有三个:
1.手机要支持UMS的话,必须要有一个sd卡,因为sd卡往往采用Windows支持的分区格式。如果想把内部存储空间通过UMS挂载到Windows上,则内部存储空间需采用特定的分区格式。这对某些手机而言根本不可行。因为内部存储空间本身可能就是一个设备,它们采用统一的分区格式。不能因为需要使用UMS,而再增加一块特定的分区格式的存储设备。
2.UMS挂载到PC后,PC操作系统拥有绝对的控制权。此时,Android系统无法操作这些设备。
3.window所占市场份额较大,故即使linux,MacOS支持力度不够,Android也要集成的;
MTP的主要缺点:
1.传输大文件的速度较慢 ??
2.MTP不能直接修改文件本身,只能先拷贝到本地修改,完毕后再拷贝回去

MTP协议介绍

MTP使用者包括两个部分,分别为Initiator和Resoponder

  1. Initiator:主要是指USB Host,例如PC机,笔记本等,协议规定所有的MTP操作只能由Initator发起
  2. Responder:一般是诸如数码相机,智能手机等存储媒体文件的设备,Responder在MTP中的作用就是处理Initator发起的请求。同时,它还会根据自身状态的变化发送Event以通知Initator.

MTP 协议栈

  1. Pyshical Layer(物理层):物理层在MTP协议中用来传输数据。目前有三种物理层可供MTP使用。它们分别是USB:其主要特点是传输文件,同步媒体文件时速度快,而且可以变工作边充电,这是目前用的最多的一种方式;IP:基于IP的MTP(简称MTP/TP)将通过UPnp来匹配和发现设备。它是家庭网络中最理想的传输方式;Bluetooth:MTP/BT是最省电,同时速度最慢的一种传输方式,用处较少;
  2. 传输层:MTP中,数据传输格式遵循PTP协议
  3. 命令层:实现了MTP协议中的各种命令;

MTP采用命令-应答方式来工作,(Initator发送命令给Responder处理,Responser反馈处理结果),这种方式主要特点有:

  1. 所有MTP命令均以Package(数据包)的方式在设备两端进行传递
  2. Initiator必须接收到前一条消息处理结果,无论是成功或者超时后,才能发送下一条消息

内存管理(一)硬件篇

Posted on 2018-06-17 | In 内存管理

一.经典存储结构图

avatar

L0(寄存器)->CPU 寄存器保存来自高速缓存的字
L1(SRAM)->高速缓存取自L2高速缓存行
L2(SRAM)->高速缓存取自L3高速缓存的高速缓存行
L3(SRAM)->高速缓存保存自内存的高速缓存行
L4(内存)->内存保存自磁盘缓存的磁盘块
L5(磁盘缓存)->磁盘缓存保存取自磁盘的磁盘块
L6磁盘

cpu从磁盘中加载数据,放到内存,之后再放到告诉缓存

二.虚拟地址和物理地址

在旧的手机中,内存可能只有1G,但是每个进程在执行的时候都仿佛手机有4g内存;
物理地址(Physical Address):CPU地址总线传来的地址,由硬件电路控制其含义。物理地址中有很大一部分是留给内存条中的内存的但也常被映射到其他存储器上如显存,BIOS等),在没有使用虚拟存储器的机器上,虚拟地址被直接送到内存总线上,使具有相同物理存储器被读写;而在使用了虚拟存储器的情况下,虚拟具体地址不是被直接送到内存地址总线上,而是送到存储器管理单元MMU,把虚拟地址映射为物理地址;我们把上面实际的1G内存叫做:物理地址
虚拟地址(Virtual Address):是逻辑地址到物理地址变换之间的中间层;进程访问到的叫做虚拟地址;
虚拟内存有以下几个作用:
1.内存访问保护
有虚拟内存,我们可以通过设置段界限或页表想来设定软件运行时的访问空间,确保软件运行使不越界;
2.按需分页(lazy load技术)
可以让软件在没有访问某虚拟内存地址时,不分配虚拟地址,在实际访问的时候,在动态分配物理内存
建立虚拟内存到物理内存的页映射关系;
3.页换入换出(page swap in/out)
把不经常访问的数据所占的内存空间临时写到硬盘上,这样可以腾出更多的空闲空间出来给到经常访问的数据;当cpu访问到不经常访问的数据时,再把数据从硬件读入到内存中;
4.写时复制(copy on write)
两个虚拟页的数据相同时,可只分配一个物理页框,这样如果对两个虚拟页的访问是只读方式,这两个虚拟页可以共享页框,节省空间;如果当CPU对其中一个虚拟页进行了写操作,那么这两个虚拟页的数据内容不同,需要分配一个新的物理页框,并将物理页框标记为可写,这样两个虚拟页面将映射到不同的物理页帧,确保整个内存空间的正确访问。

二.页,页表,MMU

在讲虚拟地址到物理地址之中再补充几个概念:
页(page)
把APP的虚拟地址切分程若干个大小相等(4K)的片,每一片就是我们说的页
页框(frame)
*把物理内存页按“页”的大小切分为若干大小相等的片,每一片,就是我们所说的页框

三.cpu寻找页面过程

CPU获取数据主要有两步:
a.通过虚拟地址获取物理地址
b.根据物理地址获取数据

获取物理地址

获取物理地址
[a].CPU向MMU发送虚拟地址
[b].MMU查询快表TLB
块表命中:从块表中获取物理地址,由MMU继续根据物理地址匹配数据页步骤[a]
块表不命中:查询页表步骤[c]
[c]:从高速缓存查询页表
“高速缓存”缓存页框,而页表存储于页框中,因此读取页表实际上也是读页(页表的物理地址有单独的寄存器保存)
高速缓存命中:从高速缓存获取物理地址,并更新快表,进入[步骤a]
高速缓存不命中:查询内存中的页表[步骤d]
[d]从内存中查询页表
页表保存了所有虚拟地址的映射关系,而不管页是否有映射物理页框。因此从内存页表中肯定能“命中”页。从页表获取虚拟地址的映射关系后,进入步骤e
[e]把查询的页表想记录到高速缓存
[f]MMU从高速缓存中获取页表项
虚拟地址有分配物理页框;转换物理地址并更新块表,由MMU继续根据物理地址匹配数据页
虚拟地址没分配物理页框:触发缺页中断
[g]进入缺页中断处理程序
[h]为虚拟页分配物理页框
如果无空闲物理页框,则根据LRU算法选择需要淘汰的页,要淘汰的页如果是脏数据就回刷,否则直接丢弃或置换到磁盘的交换分区中
然后,从磁盘中获取页信息更新到物理页框,更新内存页表
[i]缺页中断处理的最后
修改CPU寄存器,使得重新启动导致缺页的指令,返回[步骤a]重新执行

根据物理地址获取实际数据

获取数据
[A]MMU获取到物理地址后,根据物理地址查询高速缓存
高速缓存命中:CPU直接从高速缓存获取数据
高速缓存不命中:查询物理内存[步骤B]
[B]根据物理地址,获取物理内存中的数据
[C]硬件实现把数据页记录到高速缓存中
[D]cpu直接从高速缓存中获取数据

123

dongka

21 posts
11 categories
13 tags
© 2020 dongka
Powered by Hexo
|
Theme — NexT.Pisces v5.1.4