目前国内出版社引进的英文技术原版书太少了,大多数还是出版一些国人翻译的版本。我不知道直接引进原版书和找人翻译在成本方面有多大差距,但是凭心而论,很多翻译的书真是不敢恭维,不客气地讲,感觉有些翻译者似乎自己都没看明白原著的意思。毕竟目前很多先进的技术和经典的书籍都是从西方传过来的,也是用英文写的。读原汁原味的书,可以更准确地理解原著的意思,也可以提高自己的英文水平。所以真的很希望国内的出版社可以多引进文技术原版书!
作者:nanxiao
Linux kernel 笔记 (55)——抢占(Preemption)
在Linux
下,一个task
运行在user-mode
时,是总可以被抢占的(preemptible
):kernel
通过正常的clock tick
中断来切换task
。
Linux kernel
在2.6
版本之前,是不支持kernel-mode
抢占的:比如task
执行了系统调用,则只能等调用执行完毕,才能让出CPU
;或者task
的kernel-mode
代码主动调用schedule
来调度其它task
运行。从2.6
版本开始,Linux
支持了kernel-mode
抢占,因此除非kernel-mode
代码关闭了local CPU
的中断,否则它任何时候都可能被抢占。
参考资料:
Preemption under Linux。
为什么单CPU没有“memory reorder”问题?
这篇文章提到单核系统上不会有“memory reorder
”问题:
Two threads being timesliced on a single CPU core won’t run into a reordering problem. A single core always knows about its own reordering and will properly resolve all its own memory accesses. Multiple cores however operate independently in this regard and thus won’t really know about each other’s reordering.
仍以Memory Reordering Caught in the Act的图为例:
其实可以这样理解:单核CPU
系统上,多个线程实际是交替顺序执行的,无法真正做到“并行”。无论两个线程或多个线程的代码如何乱序执行,CPU
知道它们原本应该的执行顺序,一旦这种乱序会改变程序的运行结果,CPU
会做出相应的“补救”措施,比如丢弃结果,重新执行等等,来保证代码会按照应该执行的顺序执行。所以“memory reorder
”问题不会在单核系统上出现。
参考资料:
Why doesn’t the instruction reorder issue occur on a single CPU core?;
preempt_disable的问题。
Linux kernel 笔记 (54)——如何选择“spinlock”或“mutex”
ELDD
中提到如何选择spinlock
和mutex
:
If the critical section needs to sleep, you have no choice but to use a mutex. It’s illegal to schedule,preempt, or sleep on a wait queue after acquiring a spinlock.
Because mutexes put the calling thread to sleep in the face of contention, you have no choice but to use spinlocks inside interrupt handlers.
SystemTap 笔记 (13)—— Statistical aggregate
Statistical aggregate
主要用来统计一组数据。它使用“<<< value
”运算来把一个value
加到这个集合里。举个例子,假设目前是个空集合,执行“<<< 1
”以后,集合里有了一个元素:1
;再执行“<<< 2
”以后,集合里有了两个元素:1
和2
。还有一些针对statistical aggregate
的运算:count
,avg
等等。通过以下例子,可以很容易知道这些运算的意义:
# cat test.stp
#!/usr/bin/stap
global reads
probe vfs.read
{
reads[execname(),pid()] <<< $count
}
probe timer.s(3)
{
foreach([execname, pid] in reads)
{
if (execname == "stapio")
{
printf("count (%s %d) : %d \n", execname, pid, @count(reads[execname, pid]))
printf("sum (%s %d) : %d \n", execname, pid, @sum(reads[execname, pid]))
printf("min (%s %d) : %d \n", execname, pid, @min(reads[execname, pid]))
printf("max (%s %d) : %d \n", execname, pid, @max(reads[execname, pid]))
printf("avg (%s %d) : %d \n", execname, pid, @avg(reads[execname, pid]))
exit()
}
}
}
# ./test.stp
count (stapio 10762) : 17
sum (stapio 10762) : 1982472
min (stapio 10762) : 8196
max (stapio 10762) : 131072
avg (stapio 10762) : 116616
SystemTap 笔记 (12)—— Associate array和foreach
SystemTap
也提供associate array
,并且必须是global
变量:
global array_name[index_expression]
最多可以有9
个index_expression
,它们之间用,
分割:
device[pid(),execname(),uid(),ppid(),"W"] = devname
可以用if
语句来检查某个key
是否存在:
if([index_expression] in array_name) statement
以下面程序为例:
# cat test.stp
#!/usr/bin/stap
global reads
probe vfs.read
{
reads[execname()] ++
}
probe timer.s(3)
{
printf("=======\n")
foreach (count in reads+)
printf("%s : %d \n", count, reads[count])
if(["stapio"] in reads) {
printf("stapio read detected, exiting\n")
exit()
}
}
# ./test.stp
=======
systemd-udevd : 4
gmain : 5
avahi-daemon : 11
stapio : 17
stapio read detected, exiting
可以用delete
操作来删除一个元素或是整个数组:
delete removes an element.
The following statement removes from ARRAY the element specified by the index tuple. The value will no longer be available, and subsequent iterations will not report the element. It is not an error to delete an element that does not exist.
delete ARRAY[INDEX1, INDEX2, …]
The following syntax removes all elements from ARRAY:
delete ARRAY
foreach
是输出associate array
的一个重要方法:
General syntax:
foreach (VAR in ARRAY) STMT
The foreach statement loops over each element of a named global array, assigning the current key to VAR. The array must not be modified within the statement. If you add a single plus (+) or minus (-) operator after the VAR or the ARRAY identifier, the iteration order will be sorted by the ascending or descending index or value.The following statement behaves the same as the first example, except it is used when an array is indexed with a tuple of keys. Use a sorting suffix on at most one VAR or ARRAY identifier.
foreach ([VAR1, VAR2, …] in ARRAY) STMT
You can combine the first and second syntax to capture both the full tuple and the keys at the same time as follows.
foreach (VALUE = [VAR1, VAR2, …] in ARRAY) STMT
The following statement is the same as the first example, except that the limit keyword limits the number of loop iterations to EXP times. EXP is evaluated once at the beginning of the loop.
foreach (VAR in ARRAY limit EXP) STMT
下面这个例子很好地解释了如何用foreach
操作associate array
:
# cat test.stp
#!/usr/bin/stap
global reads
probe vfs.read
{
reads[pid(), execname()]++
}
probe timer.s(3)
{
printf("======Total=====\n")
foreach ([pid, name] in reads)
printf("%d %s: %d\n", pid, name, reads[pid, name])
printf("======Another Total=====\n")
foreach (val = [pid, name] in reads)
printf("%d %s: %d\n", pid, name, val)
printf("======PID Ascending=====\n")
foreach ([pid+, name] in reads limit 3)
printf("%d %s: %d\n", pid, name, reads[pid, name])
printf("======Count Descending=====\n")
foreach ([pid, name] in reads- limit 3)
printf("%d %s: %d\n", pid, name, reads[pid, name])
exit()
}
执行如下:
# ./test.stp
======Total=====
14367 stapio: 17
976 gmain: 5
791 avahi-daemon: 11
806 irqbalance: 16
14368 systemd-udevd: 1
432 systemd-udevd: 3
======Another Total=====
14367 stapio: 17
976 gmain: 5
791 avahi-daemon: 11
806 irqbalance: 16
14368 systemd-udevd: 1
432 systemd-udevd: 3
======PID Ascending=====
432 systemd-udevd: 3
791 avahi-daemon: 11
806 irqbalance: 16
======Count Descending=====
14367 stapio: 17
806 irqbalance: 16
791 avahi-daemon: 11
首先输出associate array
中的所有内容(使用两种不同方式),接着分别按PID
升序和associate array
中的value
降序输出前三个。
Haskell笔记 (2)—— if语句
(1)
The difference between Haskell’s if statement and if statements in imperative languages is that the else part is mandatory in Haskell.
在Haskell
中,if
语句的else
部分是必须有的:
doubleSmallNumber x = if x > 100
then x
else X * 2
否则会有以下编译错误:
parse error in if statement: missing required else clause
(2)
Another thing about the if statement in Haskell is that it is an expression. An expression is basically a piece of code that returns a value. 5 is an expression because it returns 5, 4 + 8 is an expression, x + y is an expression because it returns the sum of x and y. Because the else is mandatory, an if statement will always return something and that’s why it’s an expression.
Haskell笔记 (1)—— 函数
(1)
In Haskell, functions are called by writing the function name, a space and then the parameters, separated by spaces.
Haskell
中函数调用不使用括号,使用空白符隔开函数名和参数:
> min 9 10
9
(2)
If a function takes two parameters, we can also call it as an infix function by surrounding it with backticks.
如果函数有两个参数,可以使用中缀表达法。但要注意“`”符号:
> 9 `min` 10
9
> 9 min 10
<interactive>:10:1:
Non type-variable argument
in the constraint: Num ((a -> a -> a) -> a -> t)
(Use FlexibleContexts to permit this)
When checking that ‘it’ has the inferred type
it :: forall a a1 t.
(Num a1, Num ((a -> a -> a) -> a1 -> t), Ord a) =>
t
(3)
Functions in Haskell don’t have to be in any particular order.
(4)
Side effects are essentially invisible inputs to, or outputs from, functions. In Haskell, the default is for functions to not have side effects: the result of a function depends only on the inputs that we explicitly provide. We call these functions pure; functions with side effects are impure.
If a function has side effects, we can tell by reading its type signature—the type of the function’s result will begin with IO:
ghci> :type readFile
readFile :: FilePath -> IO String
Haskell’s type system prevents us from accidentally mixing pure and impure code.
(5)
Haskell doesn’t have a return keyword, because a function is a single expression, not a sequence of statements. The value of the expression is the result of the function.
SLES12版本上Xen的一些变化
今天在网上找到一篇文档,描述了SLES12
版本上Xen
的一些变化:
(1)grub2
SLES12
上使用grub2
配置Xen
参数。以配置dom0_max_vcpus
为例:
a)SLES11
使用/boot/grub/menu.lst
(参考这里);
b)SLES12
使用/etc/default/grub
(参考这里)。
(2)xm/xend
已经废弃了,要使用xl/libxl
。下图做了一个简单对比:
(3)SLES12 Xen Stack
:
• Xen 4.4.1
• kernel 3.12.x
• libvirt 1.2.5
• virt-install 1.1.x, vm-install 1.x.x
• virt-manager 1.1.x
“Memory order”分析笔记
为什么会发生memory reorder
?一言以蔽之,因为性能。
在支持memory reorder
的系统上,有以下3
种order
需要考虑:
Program order: the order in which the memory operations are specified in the code running on a given CPU.
Execution order: the order in which the individual memory-reference instructions are executed on a given CPU. The execution order can differ from program order due to both compiler and CPU-implementation optimizations.
Perceived order: the order in which a given CPU perceives its and other CPUs’ memory operations. The perceived order can differ from the execution order due to caching, interconnect and memory-system optimizations. Different CPUs might well perceive the same memory operations as occurring in different orders.
Program order
是代码里访问内存的顺序。Execution order
是代码在CPU
上实际执行的顺序,由于编译器优化和CPU
的实现,实际指令执行的顺序有可能和代码顺序不一样。Perceived order
是CPU
用来“感知”自己或者其它CPU
对内存操作,由于caching
,interconnect
等原因,这个顺序有可能与代码实际的execution order
不同。
关于memory order
的总结:
A given CPU always perceives its own memory operations as occurring in program order. That is, memory-reordering issues arise only when a CPU is observing other CPUs’ memory operations.
An operation is reordered with a store only if the operation accesses a different location than does the store.
Aligned simple loads and stores are atomic.
Linux-kernel synchronization primitives contain any needed memory barriers, which is a good reason to use these primitives.
参考资料:
Memory Reordering Caught in the Act;
Memory Ordering in Modern Microprocessors, Part I。