AUTHOR: Joseph Yang (杨红刚) <ganggexiongqi@gmail.com>
CONTENT: trace-clock-32-to-64.c 中synthetic_tsc 结构 设计分析初步
NOTE: linux2.6.38.6
LAST MODIFIED:10-09-2011
-----------------------------------------------------------------------------------------------------------
Distributed and Embedded System Lab (分布式嵌入式系统实验室,兰州大学)
===============================================================
static DEFINE_SPINLOCK(synthetic_tsc_lock); // 用来保护synthetic_tsc_refcount, synthetic_tsc_enabled
//tsc_timer, synthetic_tscstatic 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);
=========================================================================
会直接修改 synthetic_tsc 值的函数:
1. static void update_synthetic_tsc(void) //* Called from IPI or timer interrupt */
2. void _trace_clock_write_synthetic_tsc(u64 value) // 使用时关中断
3. static void prepare_synthetic_tsc(int cpu) // 初始化时使用
-------------------------------synthetic tsc 的设计
1. 时钟源
利用硬件时钟源(32位)作为更新的依据。
2. 利用双缓冲区同步对时钟的读写。[见后面 synthetic_tsc_struct结构的分析 ]
3. 异步地更新时钟的值:
- 在硬件源“溢出前“// 使用内核定时器,在回调函数中实现
- 读取时钟值时
- 初始化时和显示地设置时钟的值时
------------ synthetic_tsc_struct结构的分析
对于为什么下面的结构这样设计,我的理解: //这么设计的好处,您的观点请留言!!
简化 synthetic_tsc_struct 结构为,
struct synthetic_tsc_struct {
data[2];
index; /* 对索引的更新都是 原子的*/
}synthetic_tsc;
写synthetic_tsc:
1> new_index = 1 - synthetic_tsc.index; // 非原子的
2> synthetic_tsc.data[new_index] = NEW_VAL; // 非原子的
---------------------------------------------------------------------------
3> synthetic_tsc.index = new_index; // 原子的
对 synthetic_tsc的读操作,没有更新 index 也没有改变 synthetic_tsc中的data的值。
(读操作:1. 原子的获得index
2. 读取 )
而对 synthetic_tsc执行写操作函数有三个:
static void update_synthetic_tsc(void) ///* Called from IPI or timer interrupt */
void _trace_clock_write_synthetic_tsc(u64 value) //关中断时使用
static void prepare_synthetic_tsc(int cpu) // 初始化是使用
使用这些函数的实体有:
1. tsc_timer_fct // 更新 synthetic tsc的值
2. hotcpu_callback // 在CPU状态改变时,合理设置 synthetic tsc 和 tsc_timer
导出的函数有:
EXPORT_SYMBOL_GPL(trace_clock_read_synthetic_tsc); //****
EXPORT_SYMBOL_GPL(get_synthetic_tsc);
EXPORT_SYMBOL_GPL(put_synthetic_tsc);
这样我的总结就是:
有多个 实体 在 写 synthetic tsc,而有多个实体在读 synthetic tsc。
但是写操作被严格控制(如关中断时,或者 在 timer interrupt 中,
或者在初始化时)
最重要的是对 index的更新是原子的,这样就保证了多个读操作
和写操作不会产生竞争,从而也避免的锁的使用。
不知道的我的理解对不对?
----------------写和写之间要严格控制
写和写之间是有冲突的,这个冲突也会影响到读进程。
所以写和写之间要严格控制。???怎么控制的呢???
比如:两个写进程 W1, W2,一个读进程R1
初始时, data[0] = 0, data[1] = 1, index = 0
在下面的序列中会有冲突,
W1: read index // index = 0
index1 = 1- index // index1 = 1
W2: read index // index = 0
index2 = 1- index // index2 = 1
W1: write data[index1] = 7 // data[1] = 7
W1: index = index1 // index = 1
R1: atomic read index // index* = 1
W2: write data[index2] = 8 // data[1] = 8 // <----------<<<< [1]
W2: index = index2 // index = 1
[1]步骤不是原子的,如果W2在写操作的过程中被打断,转到R1读取
data[1] 的值,则 R1读到的值是被破坏的值。产生了冲突!!!
--------------- synthetic tsc 的设计评价
1. 解决了哪些问题?
- 硬件时钟源溢出的处理
- 同步时钟的读写
- CPU热插拔事件处理