kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

乘2加1

两个数A B,A<B,两种操作:A=A+1 或 A=A*2,求A到B的最少操作次数。

首先如果A、B的二进制前缀不一样则一直A=A+1

然后A=A<<1,A、B前缀不一样再A=A+1

TCP拥塞控制窗口有效性验证机制

blog.csdn.net/zhangskd/article/details/7609465

概述

问题1:当发送方长时间受到应用程序的限制,不能发送数据时,会使拥塞窗口无效。TCP是根据拥塞窗口来动态地估计网络带宽的。发送方受到应用程序的限制后,没有数据可以发送。那么此时的拥塞窗口就不能准确的反应网络状况,因为这个拥塞窗口是很早之前的。

问题2:当发送方受到应用程序限制,不能利用完拥塞窗口,会使拥塞窗口的增长无效。TCP不断调整cwnd来测试网络带宽。如果不能完全使用掉cwnd,就不知道网络能否承受得了cwnd的数据量,这种情况下的cwnd增长是无效的。

原理

TCP sender受到的两种限制

(1) application-limited :when the sender sends less than is allowed by the congestion or receiver window.

(2) network-limited:when the sender is limited by the TCP window. More precisely, we define a network-limited period as any period when the sender is sending a full window of data.

问题1描述

TCP’s congestion window controls the number of packets a TCP flow may have in the network at any time. However, long periods when the sender is idle or application-limited can lead to the invalidation of the congestion window, in that the congestion window no longer reflects current information about the state of the network.

The congestion window is set using an Additive-Increase, Multiplicative-Decrease(AIMD) mechanism that probes for available bandwidth, dynamically adapting to changing network conditions. This AIMD works well when the sender continually has data to send, as is typically the case for TCP used for bulk-data transfer. In contrast, for TCP used with telnet applications, the data sender often has little or no data to send, and the sending rate is often determined by the rate at which data is generated by the user.

问题2描述

An invalid congestion window also results when the congestion window is increased (i.e., in TCP’s slow-start or congestion avoidance phases) during application-limited periods, when the previous value of the congestion window might never have been fully utilized. As far as we know, all current TCP implementations increase the congestion window when an acknowledgement arrives, if allowed by the receiver’s advertised window and the slow-start or congestion avoidance window increase algorithm, without checking to see if the previous value of the congestion window has in fact been used.

This document proposes that the window increase algorithm not be invoked during application- limited periods. This restriction prevents the congestion window from growing arbitrarily large, in the absence of evidence that the congestion window can be supported by the network.

实现(1)

发送方在发送数据包时,如果发送的数据包有负载,则会检测拥塞窗口是否超时。如果超时,则会使拥塞窗口失效并重新计算拥塞窗口。然后根据最近接收段的时间,确定是否进入pingpong模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* Congestion state accounting after a packet has been sent. */  
static void tcp_event_data_sent (struct tcp_sock *tp, struct sock *sk)  
{  
	struct inet_connection_sock *icsk = inet_csk(sk);  
	const u32 now = tcp_time_stamp;  
  
	if (sysctl_tcp_slow_start_after_idle &&   
		(!tp->packets_out && (s32) (now - tp->lsndtime) > icsk->icsk_rto))  
		tcp_cwnd_restart(sk, __sk_dst_get(sk)); /* 重置cnwd */  
  
	tp->lsndtime = now; /* 更新最近发包的时间*/  
  
	/* If it is a reply for ato after last received packets,  
	 * enter pingpong mode. */  
	if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk.icsk_ack.ato)  
		icsk->icsk_ack.pingpong = 1;  
}  

tcp_event_data_sent()中,符合三个条件才重置cwnd:

(1)tcp_slow_start_after_idle选项设置,这个内核默认置为1 (2)tp->packets_out == 0,表示网络中没有未确认数据包 (3)now - tp->lsndtime > icsk->icsk_rto,距离上次发送数据包的时间超过了RTO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* RFC2861. Reset CWND after idle period longer RTO to "restart window". 
 * This is the first part of cnwd validation mechanism. 
 */  
static void tcp_cwnd_restart (struct sock *sk, const struct dst_entry *dst)  
{  
	struct tcp_sock *tp = tcp_sk(sk);  
	s32 delta = tcp_time_stamp - tp->lsndtime;  
  
	/* 关于tcp_init_cwnd()可见上一篇blog.*/  
	u32 restart_cwnd = tcp_init_cwnd(tp, dst);  
	u32 cwnd = tp->snd_cwnd;  
	  
	/* 触发拥塞窗口重置事件*/  
	tcp_ca_event(sk, CA_EVENT_CWND_RESTART);  
  
	/* 阈值保存下来,并没有重置。*/  
	tp->snd_ssthresh = tcp_current_ssthresh(sk);  
	restart_cwnd = min(restart_cwnd, cwnd);  
  
	/* 闲置时间每超过一个RTO且cwnd比重置后的大时,cwnd减半。*/  
	while((delta -= inet_csk(sk)->icsk_rto) > 0 && cwnd > restart_cwnd)  
		cwnd >> 1;  
  
	tp->snd_cwnd = max(cwnd, restart_cwnd); /* 取其大者!*/  
	tp->snd_cwnd_stamp = tcp_time_stamp;  
	tp->snd_cwnd_used = 0;  
}  

那么调用tcp_cwnd_restart()后,tp->snd_cwnd是多少呢?这个是不确定的,要看闲置时间delta、闲置前的cwnd、路由器中设置的initcwnd。当然,最大概率的是:拥塞窗口降为闲置前cwnd的一半。

实现(2)

在发送方成功发送一个数据包后,会检查从发送队列发出而未确认的数据包是否用完拥塞窗口。 如果拥塞窗口被用完了,说明发送方收到网络限制; 如果拥塞窗口没被用完,且距离上次检查时间超过了RTO,说明发送方收到应用程序限制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* Congestion window validation.(RFC2861) */  
static void tcp_cwnd_validate(struct sock *sk) {  
	struct tcp_sock *tp = tcp_sk(sk);  
  
	if (tp->packets_out >= tp->snd_cwnd) {  
		/* Network is feed fully. */  
		tp->snd_cwnd_used = 0; /*不用这个变量*/  
		tp->snd_cwnd_stamp = tcp_time_stamp; /* 更新检测时间*/  
  
	} else {  
		/* Network starves. */  
		if (tp->packets_out > tp->snd_cwnd_used)  
			tp->snd_cwnd_used = tp->packets_out; /* 更新已使用窗口*/  
  
			/* 如果距离上次检测的时间,即距离上次发包时间已经超过RTO*/  
			if (sysctl_tcp_slow_start_after_idle &&  
				(s32) (tcp_time_stamp - tp->snd_cwnd_stamp) >= inet_csk(sk)->icsk_rto)  
				tcp_cwnd_application_limited(sk);  
	}  
}  

在发送方收到应用程序的限制期间,每隔RTO时间,都会调用tcp_cwnd_application_limited()来重新设置sshresh和cwnd,具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. 
 * As additional protections, we do not touch cwnd in retransmission phases, 
 * and if application hit its sndbuf limit recently. 
 */  
void tcp_cwnd_application_limited(struct sock *sk)  
{  
	struct tcp_sock *tp = tcp_sk(sk);  
  
	/* 只有处于Open态,应用程序没受到sndbuf限制时,才进行 
	 * ssthresh和cwnd的重置。 
	 */  
	if (inet_csk(sk)->icsk_ca_state == TCP_CA_Open &&   
		sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) {  
  
		/* Limited by application or receiver window. */  
		u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk));  
		u32 win_used = max(tp->snd_cwnd_used, init_win);  
  
		/* 没用完拥塞窗口*/  
		if (win_used < tp->snd_cwnd) {  
			/* 并没有减小ssthresh,反而增大,保留了过去的信息,以便之后有数据发送 
			  * 时能快速增大到接近此时的窗口。 
			  */  
			tp->snd_ssthresh = tcp_current_ssthresh(sk);   
			/* 减小了snd_cwnd */  
			tp->snd_cwnd = (tp->snd_cwnd + win_used) >> 1;  
		}  
		tp->snd_cwnd_used = 0;  
	}  
	tp->snd_cwnd_stamp = tcp_time_stamp; /* 更新最近的数据包发送时间*/  
}  

发送方受到应用程序限制,且限制的时间每经过RTO后,就会调用以上函数来处理snd_ssthresh和snd_cwnd:

(1)snd_ssthresh = max(snd_ssthresh, ¾ cwnd)

慢启动阈值并没有减小,相反,如果此时cwnd较大,ssthresh会相应的增大。ssthresh是一个很重要的参数,它保留了旧的信息。这样一来,如果应用程序产生了大量的数据,发送方不再受到限制后,经过慢启动阶段,拥塞窗口就能快速恢复到接近以前的值了。

(2)snd_cwnd = (snd_cwnd + snd_cwnd_used) / 2

因为snd_cwnd_used < snd_cwnd,所以snd_cwnd是减小了的。减小snd_cwnd是为了不让它盲目的增长。因为发送方没有利用完拥塞窗口,并不能检测到网络是否能承受该拥塞窗口,这时的增长是无根据的。

结论

在发送完数据包后,通过对拥塞窗口有效性的检验,能够避免使用不合理的拥塞窗口。

拥塞窗口代表着网络的状况,通过避免使用不合理的拥塞窗口,就能得到正确的网络状况,而不会采取一些不恰当的措施。

在上文的两种情况下,通过TCP的拥塞窗口有效性验证机制(TCP congestion window validationmechanism),能够更合理的利用网络、避免丢包,从而提高传输效率。

Reference

RFC2861

Android 系统基本

http://tieba.baidu.com/p/2687199243?see_lz=1

二、锁定频率和核心

1. 了解热插拔

热插拔驱动(Hotplug Driver)是控制cpu负载控制核心上线下线的驱动

注意:所有热插拔驱动都是根据负载调节cpu上下线,只是策略有不同。这不是“高通异步专利”

高通机器默认热插拔:mpdecision
1
/system/bin/mpdecision

这个热插拔驱动其实工作的蛮不错的。各个厂商之间略会有不同。个人建议使用8064以后机器的不使用第三方的热插拔驱动

Exynos机器热插拔:pegasusq

三星的热插拔驱动是集成在了governor(调速器)中的,这个调速器可以看作ondemand+hotplug,工作方式为多核低频

Tegra机器热插拔:hotplug

两个字:渣渣
建议使用开发者开发的热插拔驱动

2. 如何锁定cpu核心

方法1: 使用kernel tuner

方法2: 使用脚本(只针对高通机器):

1
2
3
4
5
6
7
8
9
#!/system/bin/sh

stop mpdecision
echo 0 > /sys/devices/system/cpu/cpu1/online
chmod 444 /sys/devices/system/cpu/cpu1/online
echo 0 > /sys/devices/system/cpu/cpu2/online
chmod 444 /sys/devices/system/cpu/cpu2/online
echo 1 > /sys/devices/system/cpu/cpu3/online
chmod 444 /sys/devices/system/cpu/cpu3/online

注意: 这样做将没有热插拔驱动工作,在空载时依然会有两个核心上线

3. 如何锁定频率

(1)锁定cpu频率

步骤1: 将governor设置为performance

方法很简单,用fauxclock,trickester mod,kernel tuner都可以搞定,并且不占用资源采样负载

弊端:如果不修改温度配置文件,将会受到降频影响

步骤2: 修改权限让温控进程无法对其降频

1
2
3
4
5
6
7
8
9
#!/system/bin/sh
echo 你的cpu的最大频率 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
chmod 444 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
echo 你的cpu的最大频率 > /sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq
chmod 444 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
echo 你的cpu的最大频率 > /sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq
chmod 444 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
echo 你的cpu的最大频率 > /sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq
chmod 444 /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq

注意:cpu频率以khz为单位,比如1728mhz应该在这里写为1728000

(2)锁定gpu频率

步骤1: 将governor设置为performance

方法很简单,用fauxclock,trickester mod,kernel tuner都可以搞定,并且不占用资源采样负载

弊端:如果不修改温度配置文件,将会受到降频影响

1
2
3
4
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo performance > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
echo performance > /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor
echo performance > /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor

步骤2:

1
2
echo 你的gpu的最大频率 > /sys/devices/platform/kgsl-3d0.0/kgsl/kgsl-3d0/max_gpuclk
chmod 444 /sys/devices/platform/kgsl-3d0.0/kgsl/kgsl-3d0/max_gpuclk

注意:gpu频率以hz为单位,比如400mhz应该在这里写为400000000

4. 关于锁定频率的看法

锁定频率对游戏性能很重要。根据我目前的结果来看,1.7g的krait 300似乎已经有点拖不动adreno 320了,而且随着频率降低,帧数跟着降低。但是对于日常使用来说,高频率只是一瞬间的事,并不需要多久,长期高频率对电池和发热的影响都会非常大。不推荐锁频,除非你要作性能测试

三、在调节linux设置

1. governor

(1) 什么是governor

governor大多数中文翻译为调速器,也叫调速策略。故名思议,根据cpu负载不同而如何决定提升或者降低频率靠的就是governor

(2) 为什么governor很重要

随着linux内核的更新,governor也会带来许多新功能来提升用户体验、响应速度、省电等。另外不同厂商对于不同governor的优化也是不同的。比如高通,对ondemand/msm-dcvs的优化非常好,然而对于小米用的interactive确实基本没怎么优化,在高通内核中的interactive非常之老旧,对于性能和省电都不利。在游戏中,htc的ondemand表现非常捉急,在需要提升频率的时候还按着不动,从而导致掉帧、顿卡等。切换到performance或者msm-dcvs会好不少。代表:riptide gp, asphalt 8,real racing 3

(3) 安卓上常见governor种类

cpu:

ondemand 故名思议,按需。ondemand根据cpu的负载来决定提升和降低频率,工作方式比较简单,也是最常见的一个governor

interactive 故名思议,交互。这个governor重点就是注重交互时的体验,它会比ondemand更快地提升到最高频率,而在降频时确实按照设定的时间慢慢地降。这么做会让系统很流畅,电量嘛,你懂的。

conservative 这个governor被开发者戏称为slow ondemand,它为了节电会限制cpu频率的提升,结果就是卡

performance 一直最高频

powersave 一直最低频

userspace 这个governor实质上就是让软件设定频率。比如在运行stability scaling test的时候,软件就会将其设为userspace

intellidemand intellidemand是faux123基于ondemand开发的一个governor,它和ondemand的主要区别就是在浏览网页的时候会限制频率,然后配合faux的热插拔驱动intelli-plug会获得比较好的省电效果

pegasusq 三星基于ondemand开发的热插拔governor

msm-dcvs msm(高通处理器前缀)-dcvs(dynamic clock & voltage scaling 动态频率电压调整) 这个governor是高通给krait架构开发的,具体有什么魔力我也不清楚,只是用它玩游戏的时候感觉比ondemand流畅多了

gpu:

ondemand 这个和cpu的是一样的,按需调整,根据负载决定频率

performance 永远最大频率

simple 这个governor是faux123对adreno 3xx开发的一个governor,其中参数有laziness和thresholds。前者数值分布1-10,决定的是忽略多少降频请求,数字越大性能和耗电都越高;后者是提升频率的阀值,即gpu达到多少负载提升频率,数值分布0-100,数字越大性能和耗电都越低

(3) 如何切换

最简单的当然是在fauxclock,trickester mod等软件里面切换

cpu:

1
2
3
4
echo 你的governor > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
echo 你的governor > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor
echo 你的governor > /sys/devices/system/cpu/cpu2/cpufreq/scaling_governor
echo 你的governor > /sys/devices/system/cpu/cpu3/cpufreq/scaling_governor

gpu:

1
echo 你的governor > /sys/devices/platform/kgsl-3d0.0/kgsl/kgsl-3d0/pwrscale/trustzone/governor

2. io scheduler

中文名:输入输出 调度器/io 调度器

(1) 为什么io scheduler很重要

io scheduler完全决定了磁盘的读写性能,而这对于用户体验的影响是极大打

(2) 安卓上常见io scheduler

cfq

completely-fair-quening

完全公平队列,是anticipatory模式的替代品,没有过多的做预测性调度,而是根据给定的进程io优先级,直接来分配操作的顺序。这个模式在linux上表现良好,但也许并不是最适合android的io调度模式,太强调均衡,而降低了连续读写数据的性能。

高通默认的就是这个,强烈建议改掉,根本不适合移动设备

noop

这个调度模式会把所有的数据请求直接合并到一个简单的队列里。不适合有机械结构的存储器,因为没有优化顺序,会增加额外的寻道时间。属于最简单的一个调度模式,无视io操作优先级和复杂性,执行完一个再执行一个,如果读写操作繁多的话,就会造成效率降低。

nvidia默认,有时候会造成顿卡,但是听说这个scheduler对省电比较有帮助

deadline

顾名思义,用过期时间来排序io操作顺序,保证先出现的io请求有最短的延迟时间,相对于写操作,给读操作更优先的级别。是比较好的一个调度模式。

性能不错

row

read over write

顾名思义,这个scheduler会优先处理读的请求。在移动设备上读的请求远远多于并且重要于写的请求,并且随机读取速度很重要。这个governor允许单或者双线程的读写,在同时有读写的情况下优先保证读,比较适合移动设备。

fiops

fair-iops 这个调度器虽然和cfq一样追求平均的优先级,但是是根据闪存设备重新设计的一个governor,各方面表现良好,是我列出来的五个scheduler里面性能最好的一个

如果有,强烈推荐fiops

sio

simple-io 在安卓上其实调度器越简单效果越好。sio就是最简单的一个调度器。不过还是有缺点的,就是随即读写性能不太好。在fiops出来以后,这个scheduler基本就被冷落了

3. read ahead buffer

这个其实奇怪。按理说缓存应该是越大越好,但是在安卓上好像不是这样,是越大越省电,越小系统越流畅,具体原理我也不懂。只列下方法

依旧,fauxclock,trickester mod等可以修改

命令:

emmc内置闪存:

1
echo 你想要的大小 > /sys/block/mmcblk0/quene/read_ahead_kb

sd卡:

1
echo 你想要的大小 > /sys/block/mmcblk1/quene/read_ahead_kb

默认为128k,如果想省电可以设成2048k

4. emmc entropy

entropy是一个叫混乱度的东西,好像是物理化学里面的,根据faux123的解释,闪存设备根本不需要entropy,所以就把它关掉来提高性能

fauxclock里面可以关闭

命令

1
2
echo 0 > /sys/block/mmcblk0/quene/add_random
echo 0 > /sys/block/mmcblk1/quene/add_random

5. c-states

高通从krait 200上引进,但是有bug,在krait 300上得到了修复

总共4个状态:

c0, wfi
c1, rentention
c2, standalone_power_collapse
c3, power_collapse

数字从低到高代表了睡眠程度的高低,数字越高的状态越省电

intel也有这个,haswell就是凭借着强大的c-states调整在tdp更高的情况下获得了更低的耗电和更长的续航。桌面上比如e3可以将c6状态打开,能在0.8v左右稳定在3.3g

高通的c-states和intel不一样,在平时工作的时候高通处理器进入c states的时间很少,主要集中在关屏深睡眠的时候

fauxclock可以打开,krait 300建议打开c0 c2 c3

命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
echo 1 > /sys/module/pm_8x60/modes/cpu0/wfi/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu1/wfi/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu2/wfi/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu3/wfi/idle_enabled
echo 0 > /sys/module/pm_8x60/modes/cpu0/retention/idle_enabled
echo 0 > /sys/module/pm_8x60/modes/cpu1/retention/idle_enabled
echo 0 > /sys/module/pm_8x60/modes/cpu2/retention/idle_enabled
echo 0 > /sys/module/pm_8x60/modes/cpu3/retention/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu0/standalone_power_collapse/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu1/standalone_power_collapse/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu2/standalone_power_collapse/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu3/standalone_power_collapse/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu0/power_collapse/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu1/power_collapse/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu2/power_collapse/idle_enabled
echo 1 > /sys/module/pm_8x60/modes/cpu3/power_collapse/idle_enabled

6. 不同的构图方式

从Android 4.0以后大家可以从build.prop里面发现这么几行:

1
2
debug.sf.hw=1
debug.composition.type=gpu

在4.2以后还可以看到这一行

1
persist.hwc.mdpcomp.enable=true

这就是构图方式

从谷歌4.2的build.prop的变化来看,谷歌已经开始强制使用mdp。性能更强但是耗电更低,何乐而不为

(1) 构图方式种类

cpu: 故名思议,cpu构图

gpu: gpu构图,在开发者选项中选择“关闭hw叠加层”和只设置debug.sf.hw=1都是让gpu构图

c2d: c2d构图,这个在2.x时代就已经被抛弃了,比gpu构图还烂

dyn: 这个似乎不错,但是所有高通机器的rom里面只有one的cm在用这个,而且开发者对这个构图方式的看法褒贬不一,就连这个选项是否生效都有争议。

mdp: 从firefox的开发者那里得知,新一点的机器都是有mdp管线的,比gpu构图性能更强、更省电。谷歌也因此强制使用这个构图方式

(2) 构图方式的影响

最常见的影响当然就是fps meter打开变卡了

firefox开发者的解释: https://bugzilla.mozilla.org/show_bug.cgi?id=911391

当叠加层数量低于mdp管线数量的时候,所有的构图都用mdp完成,不仅性能比gpu构图更好,而且还更省电。但是一旦叠加层数量超过mdp管线的数量,系统就会自动使用“部分mdp构图”,实质上就是要mdp和gpu合作构一帧的图。那么这个时候,就会导致性能下降

为什么打开一些overlay软件就变卡了呢?这就说明打开这类软件以后,比如fps meter,整个图层的数量已经超过了mdp的管线数量,系统启用gpu构图,导致系统、游戏流畅度下降。为什么有些人开始还不觉得fps meter对性能有影响呢?原因可能有三个:1. 他们还在4.2以下,还没用过mdp,一直都在用gpu构图;2. 他们一直都关掉了hw叠加层,也是一直用gpu构图,所以无法感知gpu构图对系统流畅度的严重影响;3. 他们打开了一些overlay软件,但是没有超过mdp的管线数量,没有进入gpu构图

构图的影响还不止这些,如果有人有one,可以试试把这一行

1
persist.hwc.mdpcomp.enable=true

从build.prop里面删掉

重启以后,反复按app抽屉的图标,对比与没删之前的流畅度。另外在贴吧等软件中,mdp构图也会增加滑动的流畅度。至于视频:1. 我没有高速摄像机;2. 这是非常容易感知的问题,耍赖不承认我是没办法的

mdp的缺点:

对于一些老的应用,mdp会造成负面影响,对流畅度负加成:比如在使用老版re管理器的时候,转移到多任务界面会有卡顿,而新版则非常流畅。 在叠加层数量超过mdp管线数量的时候,会转为“部分mdp构图”,mdp管线和gpu合作构图

不过谷歌已经强制使用mdp,随着软件更新,更快更省电的mdp构图将会逐渐替代gpu构图

四、关于作弊

很多厂商被逮着了“作弊”,其实我觉得根据不同的app调整策略不是坏事,但是你不开放给用户那就有问题了。凭什么只能跑分得到这样的待遇?厂商真的应该好好反思

1.作弊文件位置:

三星: TwDVFSApp.apk

HTC: /system/bin/pnpmgr; /system/etc/pnp.xml

NVIDIA:/system/app/NvCPLSvc.apk/res/raw/tegraprof.txt

2.如何对待?

作弊固然可耻,但是干掉这些东西又不是明智的选择。虽然这些文件有对跑分的专门配置和优化,但是它们还对普通应用程序/游戏有着配置。比如pnpmgr,它管理者省电模式、touch_boost、60fps视频cpu提频等等非常有用的调整;比如tegraprof,这里面更是有不少针对游戏优化的配置文件。关掉它们只会给用户体验减分。我希望所有厂商能够开放配置,让用户自由定制,而不是现在的加密处理。

五、关于测试的一些注意事项

  1. 注明机型,驱动版本,系统版本,内核类型(是官方还是第三方,编译器是什么。换一个编译器可以让某些性能差别达到20%)构图方式

  2. 不要在开启fps meter的同时打开其他悬窗监控软件。fps meter统计的是整个图层的平均帧数,开启其他悬窗监控软解无论刷新率调到多少都是不准的(除非overlay在fps meter上面)

  3. 测试的时候最好关掉温度进程,以防止意外降频

  4. 对比测试的时候注意变化量,在变化量超过一个的时候对比测试结果不可信

  5. 如果想反映整个游戏的帧数情况,用Adreno Profiler。在没有高速摄像机的情况下,这个比视频靠谱得多。https://developer.qualcomm.com/mobile-development/mobile-technologies/gaming-graphics-optimization-adreno/tools-and-resources

一、温度控制

很多人抱怨手机降频,其实这不是坏事,降频厉害,也是oem厂商所为,与soc厂商关系不是太大

可能抱怨最多的就是高通机器了,这里讲下高通机器的温度控制进程的基本调试

1. 开启和关闭温控进程

关闭:

1
stop thermald

开启:

1
start thermald
注意事项:

关闭温控以后,除非内核中也有温度保护,机器将不会降频,散热设计不好的机器很有可能因此烧毁。请谨慎考虑关闭温控进程

2. 降频阀值的调整

(1)了解自己手机的传感器

方法1:使用last_kmsg

1
adb pull /proc/last_kmsg

在adb目录下,找到last_kmsg文件,用记事本(推荐用notepad++/notepad2)打开,搜索sensor

方法2: 使用cat命令逐个查看

1
cat /sys/devices/virtual/thermald/thermald_zone*/temp

显示出的数值即该传感器的温度

毫无疑问,温度最高的那几个就是cpu温度传感器

(2)了解thermald配置文件

配置文件的路径在 /system/etc/thermald.conf,权限为644

注意:

对于大部分高通机器,打开即可编辑。对于HTC机器,这个文件是加密的,只能自己写。

对于三星的机器,这个文件会是一个软链,比如E330S软链到了thermald-8974.conf文件,那么你真正应该修改的文件则是thermald-8974.conf

(3)获取频率表

获取cpu频率表:

1
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies

获取gpu频率表:

1
cat /sys/devices/platform/kgsl-3d0.0/kgsl/kgsl-3d0/gpu_available_frequencies

注意: 部分三星机器,比如E330S无法查看gpu频率

(4)自己改写thermald.conf

步骤1: 了解thermald.conf的语言

1
2
3
4
5
6
7
8
9
10
11
sampling:采样时间
[tsen_tz_sensor*]:对于*号传感器的配置
thresholds:降频阀值,达到这个温度即降频
thresholds_clr:恢复阀值,达到这个温度即恢复到上一阶段配置的频率
actions:降频所采取的行动
cpu:降频cpu
gpu:降频gpu
shutdown:关机
lcd:改变屏幕亮度,+255最大
battery:不懂,但可以知道的是+1和+2,能降低温度
action_info:定义具体降频到多少

步骤2: 定义总采样时间

1
sampling 5000

数值越低采样越勤,也越耗费资源。不建议修改

步骤3: 定义传感器

1
2
3
4
5
6
[tsens_tz_sensor7]
sampling 1500
thresholds 54 57 64 70 75
thresholds_clr 51 54 57 64 70
actions gpu+cpu gpu+cpu cpu cpu cpu
action_info 400000000+1728000 320000000+1134000 1026000 918000 702000

步骤3.1:定义所需要的传感器

在你获得的传感器中,选择所需要的传感器。据我所知,绝大多数高通机器打sensor7, sensor8, sensor9都是cpu温度传感器,若要使用其他温度传感器,直接修改这个数字即可

步骤3.2:定义该传感器的采样时间

sampling 1500

数值越低,采样越勤,不建议修改

步骤3.3: 修改触发行为的温度阀值,即高于这个设定的温度就会采用当前定义的行为,比如降频

thresholds 54 57 64 70 75

步骤3.4: 修改回到上一行为的温度阀值,即低于这个设定温度就会回到上一个温度阀值所定义的行为(shutdown命令除外)

thresholds_clr 51 54 57 64 70

步骤3.5: 定义行为,最常见的就是cpu,gpu,shutdown,若要定义多个行为,则用加号相连

actions gpu+cpu gpu+cpu cpu cpu cpu

步骤3.6: 定义所采取的行为的具体数值,即降频降到多少。

action_info 400000000+1728000 320000000+1134000 1026000 918000 702000

注意: 其数值顺序必须与actions的顺序一模一样,最好与cpu和gpu频率表一致,否则容易出错。千万不要像三星官方一样敷衍了事。

3. 关于降频的看法

个人认为降频并不是一件坏事,在soc发热越来越大的今天,降频是厂商保证用户体验的一种方式之一:降低发热,降低耗电

但是我希望每个厂商都能像小米一样开发不同的模式,在需要降频省电的时候用一套温控配置,在需要性能的时候用另一套温控配置;而大多数国际厂商,比如三星,htc,nvidia,仅仅在跑分的时候使用了更高的温度配置,而且是用户无法选择的。这种行为应该表示抗议!强烈谴责!

c 文件锁flock

http://blog.csdn.net/lin_fs/article/details/7804494

头文件 #include<sys/file.h>

定义函数 int flock(int fd, int operation);

函数说明 flock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。

参数 operation有下列四种情况:
LOCK_SH 建立共享锁定。多个进程可同时对同一个文件作共享锁定。
LOCK_EX 建立互斥锁定。一个文件同时只有一个互斥锁定。
LOCK_UN 解除文件锁定状态。
LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_SH或LOCK_EX 做OR(|)组合。
单一文件无法同时建立共享锁定和互斥锁定,而当使用dup()或fork()时文件描述词不会继承此种锁定。

返回值 返回0表示成功,若有错误则返回-1,错误代码存于errno。

flock只要在打开文件后,需要对文件读写之前flock一下就可以了,用完之后再flock一下,前面加锁,后面解锁。其实确实是这么简单,但是前段时间用的时候发现点问题,问题描述如下:

一个进程去打开文件,输入一个整数,然后上一把写锁(LOCK_EX),再输入一个整数将解锁(LOCK_UN),另一个进程打开同样一个文件,直接向文件中写数据,发现锁不起作用,能正常写入(我此时用的是超级用户)。google了一大圈发现flock不提供锁检查,也就是说在用flock之前需要用户自己去检查一下是否已经上了锁,说明白点就是读写文件之前用一下flock检查一下文件有没有上锁,如果上锁了flock将会阻塞在那里(An attempt to lock the file using one of these file descriptors may be denied by a lock that the calling process has already placed via another descriptor ),除非用了LOCK_NB。一个完整的用于测试的事例代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//lockfile.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

int main()
{
	int fd,i;
	char path[] = "/home/taoyong/test.txt";
	extern int errno;
	fd = open(path,O_WRONLY|O_CREAT);
	if(fd != -1)
	{
		printf("open file %s ./n", path);
		printf("please input a number to lock the file./n");
		scanf("%d", &i);
		if (flock(fd, LOCK_EX) == 0)
		{
			printf("the file was locked./n");
		}
		else
		{
			printf("the file was not locked./n");
		}
		printf("please input a number to unlock the file./n");
		scanf("%d", &i);
		if (flock(fd, LOCK_UN)==0)
		{
			printf("the file was unlocked./n");
		}
		else
		{
			printf("the file was not unlocked./n");
		}
		close(fd);
	}
	else
	{
		printf("cannot open file %s/n", path);
		printf("errno:%d/n", errno);
		printf("errMsg:%s", strerror(errno));
	}
	return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//testprocess.c

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/file.h>

int main()
{
	int fd,i;
	char path[] = "/home/taoyong/test.txt";
	char s[] = "writing.../nwriting....../n";
	extern int errno;
	fd = open(path, O_WRONLY|O_CREAT|O_APPEND);
	if(fd!=-1)
	{
		printf("open file %s ./n",path);

		if (flock(fd,LOCK_EX|LOCK_NB) == 0)
		{
		      printf("the file was locked by the process./n");   
			if (-1 != write(fd,s,sizeof(s)))
			{
			      printf("write %s to the file %s/n", s, path);
			}
			else
			{
			      printf("cannot write the file %s/n", path);
			      printf("errno:%d/n", errno);
			      printf("errMsg:%s/n", strerror(errno));
			}       
			   
		}
		else
		{
		      printf("the file was locked by other process.Can't write.../n");
			printf("errno:%d:", errno);
		}
		close(fd);
	}
	else
	{
	  printf("cannot open file %s/n", path);
	      printf("errno:%d/n", errno);
	      printf("errMsg:%s", strerror(errno));
	}
	return 0;
}

debuginfo 编译速度

Have a look into /usr/lib/rpm/macros:

1
2
3
4
5
6
7
8
#       Compression type and level for source/binary package payloads.
#               "w9.gzdio"      gzip level 9 (default).
#               "w9.bzdio"      bzip2 level 9.
#               "w7.xzdio"      xz level 7, xz's default.
#               "w7.lzdio"      lzma-alone level 7, lzma's default
#
#%_source_payload       w9.gzdio
#%_binary_payload       w9.gzdio

binkernel.spec中加入

1
2
%_source_payload       w5.gzdio
%_binary_payload       w5.gzdio

略微降低压缩率,大大提高打包速度。kernel增加600K,debuginfo增加3M,时间从14分钟降至2分钟内