我们知道Linux进程分为下面几种状态。
TASK_RUNNING: The process is either running on CPU or waiting in a run queue to get scheduled.
TASK_INTERRUPTIBLE: The process is sleeping, waiting for some event to occur. The process is open to be interrupted by signals. Once signalled or awoken by explicit wake-up call, the process transitions to TASK_RUNNING.
TASK_UNINTERRUPTIBLE: The process state is similar to TASK_INTERRUPTIBLE except that in this state it does not process signals. It may not be desirable even to interrupt the process while in this state since it may be in the middle of completing some important task. When the event occurs that it is waiting for, the process is awaken by the explicit wake-up call.
TASK_KILLABLE:The process is sleeping killably.It works like TASK_UNINTERRUPTIBLE with the bonus that it can respond to fatal signals.TASK_UNINTERRUPTIBLE + TASK_WAKEKILL = TASK_KILLABLE
TASK_STOPPED: The process execution is stopped, it's not running, and not able to run. On receipt of signals like SIGSTOP, SIGTSTP, and so on, the process arrives at this state. The process would be runnable again on receipt of signal SIGCONT.
TASK_TRACED: A process arrives at this state while it is being monitored by other processes such as debuggers.
EXIT_ZOMBIE: The process has terminated. It is lingering around just for its parent to collect some statistical information about it.
EXIT_DEAD: The final state (just like it sounds). The process reaches this state when it is being removed from the system since its parent has just collected all statistical information by issuing the wait4() or waitpid() system call.
Process sleep
The Linux kernelprovides two ways to put a process to sleep.
The normal way to put a process to sleep is
to set the process's state to eitherTASK_INTERRUPTIBLEorTASK_UNINTERRUPTIBLEand call the scheduler's functionschedule(). This results in the process getting moved off from
the CPU run queue. If the process is sleeping in interruptible mode (by setting
its state toTASK_INTERRUPTIBLE), it can be awakened either by an explicit wake-up
call (wakeup_process()) or by signals needing processing.
However, if the process is sleeping in
uninterruptible mode (by setting its state toTASK_UNINTERRUPTIBLE), it can only be awakened by an explicit wake-up
call. It is advised to put the processes into interruptible sleep mode rather
than uninterruptible sleep mode unless you really, really need to (such during
device I/O when processing signals is difficult).
Systrace中线程的状态
在Systrace中我们常见的状态有R,R+,S,D,D|K,R和R+都是running或runnable状态。其他都是sleep状态。S是INTERRUPTIBLE的sleep。,D是UNINTERRUPTIBLE的sleep。D|K是UNINTERRUPTIBLE的但是可以被killable的sleep。
AudioOut_2-1558 ( 621)
[005] d..3 26071.007774: sched_switch: prev_comm=AudioOut_2 prev_pid=1558
prev_prio=101 prev_state=R
==> next_comm=FastMixer next_pid=1557 next_prio=96
AudioOut_2-1558 ( 621)
[004] d..3 26071.368342: sched_switch: prev_comm=AudioOut_2 prev_pid=1558
prev_prio=101 prev_state=S
==> next_comm=ims_rtp_daemon next_pid=1148 next_prio=120
AudioOut_2-1558 ( 621)
[007] d..3 26071.389107: sched_switch: prev_comm=AudioOut_2 prev_pid=1558
prev_prio=101 prev_state=R+
==> next_comm=cfinteractive next_pid=279 next_prio=0
AudioOut_2-1558 ( 621)
[006] d..3 26073.468035: sched_switch: prev_comm=AudioOut_2 prev_pid=1558
prev_prio=101 prev_state=D|K
==> next_comm=qmuxd next_pid=757 next_prio=120
Systrace状态解析
Running
从一个process call sched_switch function到目标process call sched_switch为此pid运行时间。
如:
ndroid.launcher-584 [001] d..3 12622.506890: sched_switch:
prev_comm=ndroid.launcher prev_pid=584 prev_prio=120 prev_state=R+ ==>
next_comm=Binder_1
next_pid=217 next_prio=120'
表示即将在cpu1上运行pid 217的binder_1 process。而pid为584的launcher将sleep。
Binder_1-217 [001] d..3 12622.506918: sched_switch:
prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=D ==>
next_comm=ndroid.launcher next_pid=584 next_prio=120
表示即将在cpu1上运行launcher,而pid为217的binder_1将sleep。这样pid 217的binder_1便运行了(12622.506918-12622.506890)s.
Runnable
从sched_wakeup开始到sched_switch结束。
如:
ndroid.launcher-584 [001] d..4 12622.506936: sched_wakeup:
comm=Binder_1 pid=217 prio=120 success=1 target_cpu=001
其表示PID为584的launcher在.936wakeup进程号为217的Binder_1进程,其将运行在cpu1上。此后pid为217的binder_1进程处于runnable状态。
ndroid.launcher-584
[001] d..3 12622.506950: sched_switch: prev_comm=ndroid.launcher prev_pid=584
prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=217
next_prio=120
表示即将在cpu1上运行pid 217的binder_1 process。而pid为584的launcher将sleep。此后PID为217的process变为running状态,其runnable的时间为(950-936)ms.
Sleep
从该PID call sched_switch到其他PID,此PID process进入sleep状态,当其他PID的进程sched_switch到此进程时,该进程的sleep状态结束。
如:
ndroid.launcher-584 [001] d..3 12622.506890: sched_switch:
prev_comm=ndroid.launcher prev_pid=584 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=217
next_prio=120'
表示即将在cpu1上运行pid 217的binder_1 process。而pid为584的launcher将sleep。
Binder_1-217 [001] d..3 12622.506918: sched_switch:
prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=D ==>
next_comm=ndroid.launcher next_pid=584 next_prio=120
表示即将在cpu1上运行launcher,而pid为217的binder_1将sleep。这样pid为584的进程sleep了(12622.506918-12622.506890)s.
根据被sched的进程的最近状态确定sleep的状态。
INTERRUPTIBLE Sleep
如果prev_state=R+或S则其实INTERRUPTIBLE sleep。
UNINTERRUPTIBLE Sleep
如果prev_state=D则其实UNINTERRUPTIBLE sleep。
UNINTERRUPTIBLE|KILLABLE Sleep
如果prev_state=D|K则其实UNINTERRUPTIBLE KILLABLE sleep。
Systrace 解析示例
test('importOneSequenceWithSchedWakeUp', function() {
var lines = [
'ndroid.launcher-584 [001] d..3 12622.506890: sched_switch: prev_comm=ndroid.launcher prev_pid=584 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=217 next_prio=120', // @suppress longLineCheck
' Binder_1-217 [001] d..3 12622.506918: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=D ==> next_comm=ndroid.launcher next_pid=584 next_prio=120', // @suppress longLineCheck
'ndroid.launcher-584 [001] d..4 12622.506936: sched_wakeup: comm=Binder_1 pid=217 prio=120 success=1 target_cpu=001', // @suppress longLineCheck
'ndroid.launcher-584 [001] d..3 12622.506950: sched_switch: prev_comm=ndroid.launcher prev_pid=584 prev_prio=120 prev_state=R+ ==> next_comm=Binder_1 next_pid=217 next_prio=120', // @suppress longLineCheck
' Binder_1-217 [001] ...1 12622.507057: tracing_mark_write: B|128|queueBuffer', // @suppress longLineCheck
' Binder_1-217 [001] ...1 12622.507175: tracing_mark_write: E',
' Binder_1-217 [001] d..3 12622.507253: sched_switch: prev_comm=Binder_1 prev_pid=217 prev_prio=120 prev_state=S ==> next_comm=ndroid.launcher next_pid=584 next_prio=120' // @suppress longLineCheck
];
var m = new tr.Model(lines.join('\n'), false);
assert.isFalse(m.hasImportWarnings);
var thread = m.findAllThreadsNamed('Binder_1')[0];
var timeSlices = thread.timeSlices;
assert.equal(timeSlices.length, 4);
var runningSlice = timeSlices[0];
assert.equal(runningSlice.title, 'Running');
assert.closeTo(12622506.890, runningSlice.start, 1e-5);
assert.closeTo(.918 - .890, runningSlice.duration, 1e-5);
var sleepSlice = timeSlices[1];
assert.equal(sleepSlice.title, 'Uninterruptible Sleep');
assert.closeTo(12622506.918, sleepSlice.start, 1e-5);
assert.closeTo(.936 - .918, sleepSlice.duration, 1e-5);
var wakeupSlice = timeSlices[2];
assert.equal(wakeupSlice.title, 'Runnable');
assert.closeTo(12622506.936, wakeupSlice.start, 1e-5);
assert.closeTo(.950 - .936, wakeupSlice.duration, 1e-5);
assert.equal(wakeupSlice.args['wakeup from tid'], 584);
var runningSlice2 = timeSlices[3];
assert.equal(runningSlice2.title, 'Running');
assert.closeTo(12622506.950, runningSlice2.start, 1e-5);
assert.closeTo(7.253 - 6.950, runningSlice2.duration, 1e-5);
});