AUTHOR: Joseph Yang (杨红刚) <[email protected]>
CONTENT: trace-clock-32-to-64.c 分析
NOTE: linux2.6.38.6
LAST MODIFIED:10-09-2011
-----------------------------------------------------------------------------------------------------------
Distributed and Embedded System Lab (分布式嵌入式系统实验室,兰州大学)
===============================================================
/*
* Extends a 32 bits clock source to a full 64 bits count, readable atomically
* from any execution context.
*/
- trace-clock-32-to-64.c (/usr/src/linux2.6.38.6-lttng-0.249/kernel/trace)
|- macro
|| HW_BITMASK
|| HW_LS32
|| SW_MS32
|
|- struct
|| synthetic_tsc_struct
|
|- variable
|| synthetic_tsc_refcount
|| synthetic_tsc_enabled
|| precalc_expire
|| trace_clock_read_synthetic_tsc
|| get_synthetic_tsc
|| put_synthetic_tsc
|| init_synthetic_tsc
|
|- function
|| update_synthetic_tsc +
|| _trace_clock_write_synthetic_tsc
|| trace_clock_read_synthetic_tsc
|| synthetic_tsc_ipi +
|| tsc_timer_fct +
|| precalc_stsc_interval +
|| prepare_synthetic_tsc +
|| enable_synthetic_tsc +
|| disable_synthetic_tsc +
|| hotcpu_callback +
|| get_synthetic_tsc +
|| put_synthetic_tsc +
|| init_synthetic_tsc +
=============================================
---------------- 相关变量和结构
#define HW_BITMASK ((1ULL << TC_HW_BITS) - 1)
#define HW_LS32(hw) ((hw) & HW_BITMASK)
#define SW_MS32(sw) ((sw) & ~HW_BITMASK)
static DEFINE_SPINLOCK(synthetic_tsc_lock); // 用来保护synthetic_tsc_refcount, synthetic_tsc_enabled
//tsc_timer, synthetic_tsc
static int synthetic_tsc_refcount; /* Number of readers */
static int synthetic_tsc_enabled; /* synth. TSC enabled on all online CPUs */
static DEFINE_PER_CPU(struct timer_list, tsc_timer); //在该内核定时器的回调函数
//用于在硬件时钟源溢出前,做出溢出处理,更新“伪时钟“的值。
static unsigned int precalc_expire; // 该值用来设置内核定时器tsc_timer的定时间隔。
struct synthetic_tsc_struct {
union {
u64 val;
struct {
#ifdef __BIG_ENDIAN
u32 ms32;
u32 ls32;
#else
u32 ls32;
u32 ms32;
#endif
} sel;
} tsc[2];
unsigned int index; /* Index of the current synth. tsc. */
};
static DEFINE_PER_CPU(struct synthetic_tsc_struct, synthetic_tsc);//每个CPU一个“伪tsc时钟”
外部接口:
EXPORT_SYMBOL_GPL(trace_clock_read_synthetic_tsc);
EXPORT_SYMBOL_GPL(get_synthetic_tsc);
EXPORT_SYMBOL_GPL(put_synthetic_tsc);
----------------- 函数
1.
函数:
/* Called from CPU 0, before any tracing starts, to init each structure */
static int __init init_synthetic_tsc(void)
参数:
功能:/* Called from CPU 0, before any tracing starts, to init each structure */
流程:
Precalculates the interval between the clock wraparound //precalc_stsc_interval()
注册hotcpu_callback用以在CPU的不同状态下,管理 synthetic tsc 和 tsc_timer //hotcpu_notifier
--------------------
2.
函数: 没有看懂计算公式
/*
* precalc_stsc_interval: - Precalculates the interval between the clock
* wraparounds.
*/
static int __init precalc_stsc_interval(void)
参数:
返回值: static unsigned int precalc_expire;
功能:Precalculates the interval between the clock wraparounds. (jiffies)
流程:
2^TC_HW_BITS - 1
precalc_expire = --------------------------------------------------------------------------------------------------------
2^ TRACE_CLOCK_SHIFT - 1 - TC_EXPECTED_INTERRUPT_LATENCY*HZ/1000
2^TC_HW_BITS - 1
= ------------------------------------------------------------------------------------------------------------------ ------------------------------
{trace_clock_frequency() / [ HZ * trace_clock_freq_scale()]}*2 - 1 - TC_EXPECTED_INTERRUPT_LATENCY*HZ/1000
时间*HZ : 从时间转化为对应的jiffies数(tickes)。
jiffies / HZ :从jiffies(tickes)转化为时间。
----------------
trace_clock_frequency(): HZ << TRACE_CLOCK_SHIFT, TRACE_CLOCK_SHIFT = 13
__iter_div_u64_rem(a,b,&c): 返回值是32位无符号的商,
a是64位被除数,b是32位除数,c是余数
trace_clock_freq_scale(): 返回1
#define TC_EXPECTED_INTERRUPT_LATENCY 30
#define HW_BITMASK ((1ULL << TC_HW_BITS) - 1) // 32个1
/*
* Number of hardware clock bits. The higher order bits are expected to be 0.
* If the hardware clock source has more than 32 bits, the bits higher than the
* 32nd will be truncated by a cast to a 32 bits unsigned. Range : 1 - 32.
* (too few bits would be unrealistic though, since we depend on the timer to
* detect the overflows).
*/
#define TC_HW_BITS 32
3.
函数: // kernel/trace/trace-clock-32-to-64.c
* @action: hotplug action to take
* @hcpu: CPU number
*
* Sets the new CPU's current synthetic TSC to the same value as the
* currently running CPU.
*
* Returns the success/failure of the operation. (NOTIFY_OK, NOTIFY_BAD)
*/
static int __cpuinit hotcpu_callback(struct notifier_block *nb,
unsigned long action,
void *hcpu);
参数:
返回值:
功能:在CPU的不同状态下,管理 synthetic tsc 和 tsc_timer
流程:
CPU_UP_PREPARE 或者 CPU_UP_PREPARE_FROZEN:
初始化设置 per cpu 变量 synthetic tsc 和 tsc_timer //prepare_synthetic_tsc
CPU_ONLINE 或者 CPU_ONLINE_FROZEN:
更新synthetic_tsc的值并在cpu号CPU上开始运行 tsc_time //enable_synthetic_tsc
CPU_DOWN_PREPARE 或者 CPU_DOWN_PREPARE_FROZEN:
在CPU cpu 上,删除内核定时器 tsc_timer //disable_synthetic_tsc
-------------
#define hotcpu_notifier(fn, pri) cpu_notifier(fn, pri)
#define cpu_notifier(fn, pri) { \
static struct notifier_block fn##_nb __cpuinitdata = \
{ .notifier_call = fn, .priority = pri }; \
register_cpu_notifier(&fn##_nb); \
}
#define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */
#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */
#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */
/* Used for CPU hotplug events occuring while tasks are frozen due to a suspend
* operation in progress
*/
#define CPU_UP_PREPARE_FROZEN (CPU_UP_PREPARE | CPU_TASKS_FROZEN)
4.
函数:static void prepare_synthetic_tsc(int cpu)
参数:
返回值:
功能: 初始化设置 per cpu 变量 synthetic tsc 和 tsc_timer
流程:
获得跟cpu相关的synthetic_tsc // &per_cpu
读取 synthetic tsc 的值 //trace_clock_read_synthetic_tsc
把读到的 synthetic tsc 的值存入 cpu_synth->tsc[0].val,并把指示当前synth. tsc.
的索引 cpu_synth->index 置为0
// init_timer_deferrable(&per_cpu(tsc_timer, cpu)); // ??????????
设置tsc_timer的function 为 tsc_timer_fct
设置tsc_timer的 expires 为 jiffies + precalc_expire
5.
函数:
/* Called from buffer switch : in _any_ context (even NMI) */
u64 notrace trace_clock_read_synthetic_tsc(void);
参数:
返回值: 64位的 synthetic tsc 的值
功能:读取 synthetic tsc 的值
流程:
preempt_disable_notrace() // 当前进程的preempt_count增一
读取synthetic tsc的索引(Index of the current synth. tsc. ) // ACCESS_ONCE
读取 TSC的值(只读取了32位)
/* Hardware clocksource read */ //trace_clock_read32 (arch/x86/include/asm/trace-clock.h)
溢出检测与处理://这个处理假设了溢出只发生了一次的情况
如果有溢出,则 返回 (高32位 | 低32位 + 低32向高32的一个进位)//假设TC_HW_BITS 为32
如果没有溢出,则 返回(高32位 | 低32位)
当前进程的preempt_count减一,如果需要调度,则调度// preempt_enable_notrace()
6.
函数:static void enable_synthetic_tsc(int cpu)
参数:
返回值:
功能:更新synthetic_tsc的值并在cpu号CPU上开始运行 tsc_timer
流程:
在cpu号CPU上执行synthetic_tsc_ipi以便更新synthetic_tsc的值,
并等待它在其他CPU上执行完毕 //smp_call_function_single
在cpu号CPU上开始运行 tsc_timer //add_timer_on
// tsc_timer_fct:更新synthetic_tsc的值,修改tsc_timer的超时值 为 precalc_expire
7.
函数:static void synthetic_tsc_ipi(void *info)
参数:
返回值:
功能:更新synthetic_tsc的值
流程:
更新synthetic_tsc的值 //update_synthetic_tsc()
8. ///重点分析:synthetic_tsc_struct结构的设计和操作原理 ????
函数:
/* Called from IPI or timer interrupt */
static void update_synthetic_tsc(void)
参数:
返回值:
功能:更新synthetic_tsc的值
流程:
/* Hardware clocksource read */ // trace_clock_read32()
检查本cpu上 synthetic_tsc是否有溢出:
如果有溢出,则
计算新的synthetic tsc 索引 ( Index of the current synth. tsc.) // index 0 <-> 1
用(高32位 | 低32位 + 低32向高32的一个进位)更新
cpu_synth->tsc[new_index].val //假设TC_HW_BITS 为32
更新 cpu_synth->index
如果没有溢出,则
更新 cpu_synth->tsc[cpu_synth->index].sel.ls32
9.
函数: //没有看懂为什么要这么做????//为了在硬件计数器溢出前异步的更新
//伪时钟的计数值
/*
* tsc_timer_fct : - Timer function synchronizing synthetic TSC.
* @data: unused
* Guarantees at least 1 execution before low word of TSC wraps.
*/
static void tsc_timer_fct(unsigned long data)
参数:
返回值:
功能:更新synthetic_tsc的值,修改tsc_timer的超时值 为 precalc_expire
流程:
更新synthetic_tsc的值 //update_synthetic_tsc
修改tsc_timer的超时值 为 precalc_expire //mod_timer_pinned
10.
函数:static void disable_synthetic_tsc(int cpu)
参数:
返回值:
功能:在CPU cpu 上,删除内核定时器 tsc_timer
流程:
在CPU cpu 上,删除内核定时器 tsc_timer //del_timer_sync
11.
函数:void get_synthetic_tsc(void)
参数:
返回值:
功能:对synthetic_tsc读者计数器 synthetic_tsc_refcount 加一,
第一次执行时: synthetic_tsc_enabled 置1(synth. TSC enabled on all online CPUs)
开始synthetic tsc 的运行
流程:
获得synthetic_tsc_lock锁 //spin_lock
synthetic_tsc_refcount++
如果是第一次执行,则
synthetic_tsc_enabled 置1,synth. TSC enabled on all online CPUs
对于所有在线的CPUs:
初始化设置 per cpu 变量 synthetic tsc 和 tsc_timer //prepare_synthetic_tsc
更新synthetic_tsc的值并在cpu号CPU上开始运行 tsc_timer //enable_synthetic_tsc
释放synthetic_tsc_lock 锁//spin_unlock
12.
函数:void put_synthetic_tsc(void)
参数:
返回值:
功能:对synthetic_tsc读者计数器 synthetic_tsc_refcount 减一,
最后一个读者时:synthetic_tsc_enabled关闭停止synthetic_tsc
流程:
获得synthetic_tsc_lock锁 //spin_lock
当最后一个读者时,
在所有在线的CPU执行:
在CPU cpu 上,删除内核定时器 tsc_timer // disable_synthetic_tsc
synthetic_tsc_refcount--
释放synthetic_tsc_lock 锁//spin_unlock
13.
函数: // ???被谁调用
/*
* Should only be called when interrupts are off. Affects only current CPU.
*/
void _trace_clock_write_synthetic_tsc(u64 value)
参数:
返回值:
功能: 更新 cpu_synth->tsc[].val 的值,和索引
流程:
获得本CPU的synthetic_tsc的指针 //&per_cpu
计算新的索引new_index// 0 <--> 1
cpu_synth->tsc[new_index].val = value
/* atomic change of index */
---------------------------
typedef struct {
int counter;
} atomic_t;
/*
* bits 0..12 : counter, atomically incremented
* bits 13..{32,64} : time counter, incremented each jiffy.
*/
atomic_long_t trace_clock_var; //作用????
EXPORT_SYMBOL(trace_clock_var);
-------------
#define preempt_disable_notrace() \ // 当前进程的preempt_count增一
do { \
inc_preempt_count_notrace(); \
barrier(); \
} while (0)
#define inc_preempt_count_notrace() add_preempt_count_notrace(1)
#define add_preempt_count_notrace(val) \
do { preempt_count() += (val); } while (0)
#define preempt_count() (current_thread_info()->preempt_count)
#define preempt_enable_notrace() \ // 当前进程的preempt_count减一,如果需要调度,则调度
do { \
preempt_enable_no_resched_notrace(); \ // 当前进程的preempt_count减一
barrier(); \
preempt_check_resched(); \ //如果需要调度,则调度
} while (0)
#define preempt_check_resched() \
do { \
if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ //如果需要调度
preempt_schedule(); \ // 调度
} while (0)
#define test_thread_flag(flag) \ // 测试 进程的 flag是否值位
test_ti_thread_flag(current_thread_info(), flag)
static inline int test_ti_thread_flag(struct thread_info *ti, int flag)
{
return test_bit(flag, (unsigned long *)&ti->flags);
}