Linux kernel 笔记 (54)——如何选择“spinlock”或“mutex”

ELDD中提到如何选择spinlockmutex

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”以后,集合里有了两个元素:12。还有一些针对statistical aggregate的运算:countavg等等。通过以下例子,可以很容易知道这些运算的意义:

# 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

参考资料:
Computing for Statistical Aggregates

 

SystemTap 笔记 (12)—— Associate array和foreach

SystemTap也提供associate array,并且必须是global变量:

global array_name[index_expression]

最多可以有9index_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.