VIM显示文件中的函数列表

首先安装taglist
1.到
http://www.vim.org/scripts/script.php?script_id=273下载taglist
2.把解压出来的plugin里面的文件,放到D:\Program Files\Vim\vimfiles\plugin里面
3.在 Vim 中运行 :helptags D:\Program Files\Vim\vimfiles\doc 安装文档
4.输入Tlist 即可启动函数列表功能
注意:如果启动VIM时跳出「Taglist: Exuberant ctags (
http://ctags.sf.net) not found in PATH. Plugin is not loaded.」,则需要下载ec57w32.zip (Exuberant Ctags),將其中的ctags.exe放到VIM安装时的根目录D:\Program Files\Vim\Vim70。

下面是在Tlist窗口下的按键功能介绍
Taglist window key list~
The following table lists the description of the keys that can be used
in the taglist window.

Key Description~

<CR> Jump to the location where the tag under cursor is
defined.
o Jump to the location where the tag under cursor is
defined in a new window.
P Jump to the tag in the previous (Ctrl-W_p) window.
p Display the tag definition in the file window and
keep the cursor in the taglist window itself.
t Jump to the tag in a new tab. If the file is already
opened in a tab, move to that tab.
Ctrl-t Jump to the tag in a new tab.
<Space> Display the prototype of the tag under the cursor.
For file names, display the full path to the file,
file type and the number of tags. For tag types, display the
tag type and the number of tags.
u Update the tags listed in the taglist window
s Change the sort order of the tags (by name or by order)
d Remove the tags for the file under the cursor
x Zoom-in or Zoom-out the taglist window
+ Open a fold
– Close a fold
* Open all folds
= Close all folds
[[ Jump to the beginning of the previous file
<Backspace> Jump to the beginning of the previous file
]] Jump to the beginning of the next file
<Tab> Jump to the beginning of the next file
q Close the taglist window
<F1> Display help

top 命令详解

1.作用

top命令用来显示执行中的程序进程,使用权限是所有用户。

 

2.格式

top [-] [d delay] [q] [c] [S] [s] [n]

 

3.主要参数

d:指定更新的间隔,以秒计算。

q:没有任何延迟的更新。如果使用者有超级用户,则top命令将会以最高的优先序执行。

c:显示进程完整的路径与名称。

S:累积模式,会将己完成或消失的子行程的CPU时间累积起来。

s:安全模式。

i:不显示任何闲置(Idle)或无用(Zombie)的行程。

n:显示更新的次数,完成后将会退出top。

 

4.说明

top命令是Linux系统管理的一个主要命令,通过它可以获得许多信息。这里我们结合图1来说明它给出的信息。

 

top命令的显示 (图略)

 

第一行表示的项目依次为当前时间、系统运行时间、当前系统登录用户数目、1/5/10分钟系统平均负载(一般来说,这个负载值应该不太可能超过 1 才对,除非您的系统很忙碌。 如果持续高于 5 的话,那么…..仔细的看看到底是那个程序在影响整体系统吧!)。

 

第二行显示的是所有启动的进程、目前运行、挂起 (Sleeping)的和无用(Zombie)的进程。(比较需要注意的是最后的 zombie 那个数值,如果不是 0 ,嘿嘿!好好看看到底是那个 process 变成疆尸了吧?!)(stop模式:与sleep进程应区别,sleep会主动放弃cpu,而stop是被动放弃cpu ,例单步跟踪,stop(暂停)的进程是无法自己回到运行状态的)

 

第三行显示的是目前CPU的使用情况,包括us用户空间占用CPU百分比、sy 内核空间占用CPU百分比、ni 用户进程空间内改变过优先级的进程占用CPU百分比(中断处理占用)、id 空闲CPU百分比、wa 等待输入输出的CPU时间百分比、hi,si,st 三者的意思目录还不清楚 :)

 

第四行显示物理内存的使用情况,包括总的可以使用的内存、已用内存、空闲内存、缓冲区占用的内存。

 

第五行显示交换分区使用情况,包括总的交换分区、使用的、空闲的和用于高速缓存的大小。

 

第六行显示的项目最多,下面列出了详细解释。

PID(Process ID):进程标示号 ( 每个 process 的 ID )

USER:进程所有者的用户名 ( 该 process 所属的使用者 )

PR:进程的优先级别 ( Priority 的简写,程序的优先执行顺序,越小越早被执行 )

NI:进程的优先级别数值 ( Nice 的简写,与 Priority 有关,也是越小越早被执行 )

VIRT:进程占用的虚拟内存值。

RES:进程占用的物理内存值。

SHR:进程使用的共享内存值。

S:进程的状态,其中S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值是负数。

%CPU:该进程占用的CPU使用率。

%MEM:该进程占用的物理内存和总内存的百分比。

TIME+:该进程启动后占用的总的CPU时间 ( CPU 使用时间的累加 )

Command:进程启动的启动命令名称,如果这一行显示不下,进程会有一个完整的命令行。

 

top命令使用过程中,还可以使用一些交互的命令来完成其它参数的功能。这些命令是通过快捷键启动的。

<空格>:立刻刷新。

P:根据CPU使用大小进行排序。

T:根据时间、累计时间排序。

q:退出top命令。

m:切换显示内存信息。

t:切换显示进程和CPU状态信息。

c:切换显示命令名称和完整命令行。

M:根据使用内存大小进行排序。

W:将当前设置写入~/.toprc文件中。这是写top配置文件的推荐方法。

 

o 快捷键可以调整各字段的位置,按o快捷键显示如下:


Current Fields: AEHIOQTWKNMbcdfgpjlrsuvyzX for window 1:Def
Upper case letter moves field left, lower case right
* A: PID = Process Id 0x00000400 PF_SIGNALED
* E: USER = User Name 0x00000800 PF_MEMALLOC
* H: PR = Priority 0x00002000 PF_FREE_PAGES (2.5)
* I: NI = Nice value 0x00008000 debug flag (2.5)
* O: VIRT = Virtual Image (kb) 0x00024000 special threads (2.5)
* Q: RES = Resident size (kb) 0x001D0000 special states (2.5)
* T: SHR = Shared Mem size (kb) 0x00100000 PF_USEDFPU (thru 2.4)
* W: S = Process Status
* K: %CPU = CPU usage
* N: %MEM = Memory usage (RES)
* M: TIME+ = CPU Time, hundredths
b: PPID = Parent Process Pid
c: RUSER = Real user name
d: UID = User Id
f: GROUP = Group Name
g: TTY = Controlling Tty
p: SWAP = Swapped size (kb)
j: #C = Last used cpu (SMP)
l: TIME = CPU Time
r: CODE = Code size (kb)
s: DATA = Data+Stack size (kb)
u: nFLT = Page Fault count
v: nDRT = Dirty Pages count
y: WCHAN = Sleeping in Function
z: Flags = Task Flags <sched.h>
* X: COMMAND = Command name/line

 

其中,AEHIOQTWKNMbcdfgpjlrsuvyzX 表示当前显示的可以调整的列,也就是 × 标识的列,每列都对应一个字母,现在,按‘E’ ,USER列就先下移,按‘e’ USER列就像下移,以此类推。

f 快捷键调整是否显示某列,按 f 键显示如下:


Current Fields: AEHIOQTWKNMbcdfgpjlrsuvyzX for window 1:Def
Toggle fields via field letter, type any other key to return
* A: PID = Process Id 0x00000400 PF_SIGNALED
* E: USER = User Name 0x00000800 PF_MEMALLOC
* H: PR = Priority 0x00002000 PF_FREE_PAGES (2.5)
* I: NI = Nice value 0x00008000 debug flag (2.5)
* O: VIRT = Virtual Image (kb) 0x00024000 special threads (2.5)
* Q: RES = Resident size (kb) 0x001D0000 special states (2.5)
* T: SHR = Shared Mem size (kb) 0x00100000 PF_USEDFPU (thru 2.4)
* W: S = Process Status
* K: %CPU = CPU usage
* N: %MEM = Memory usage (RES)
* M: TIME+ = CPU Time, hundredths
b: PPID = Parent Process Pid
c: RUSER = Real user name
d: UID = User Id
f: GROUP = Group Name
g: TTY = Controlling Tty
p: SWAP = Swapped size (kb)
j: #C = Last used cpu (SMP)
l: TIME = CPU Time
r: CODE = Code size (kb)
s: DATA = Data+Stack size (kb)
u: nFLT = Page Fault count
v: nDRT = Dirty Pages count
y: WCHAN = Sleeping in Function
z: Flags = Task Flags <sched.h>
* X: COMMAND = Command name/line

Flags field:
0x00000001 PF_ALIGNWARN
0x00000002 PF_STARTING
0x00000004 PF_EXITING
0x00000040 PF_FORKNOEXEC
0x00000100 PF_SUPERPRIV
0x00000200 PF_DUMPCORE

其中,AEHIOQTWKNMbcdfgpjlrsuvyzX 表示当前显示的可以调整的列,也就是 × 标识的列,每列都对应一个字母,现在,按对应列的字母,即可调整是否显示对应列,大写字母(×)标识为显示,小写(无×)标识为不显示

k 快捷键,杀死指定进程,按k,提示输入pid
        r 快捷键,调整某进程的nice值,按r,提示输入pid

F/O 指定排序列 ,用法类似f

可以看到,top命令是一个功能十分强大的监控系统的工具,对于系统管理员而言尤其重要。但是,它的缺点是会消耗很多系统资源。

Linux 系统中的buffer 与cache

一、Buffer cache简介
1、名称:buffer cache,又称bcache,其中文名称为缓冲器高速缓冲存储器,简称缓冲器高缓。另外,buffer cache按照其工作原理,又被称为块高缓。

  2、功能:在linux读写文件时,它用于缓存物理磁盘上的磁盘块,从而加快对磁盘上数据的访问。

3、大小:buffer cache的内容对应磁盘上一个块(block),块通常为1K,都是连续的。
       在linux下,为了更有效的使用物理内存,操作系统自动使用所有空闲内存作为Buffer Cache使用。当程序需要更多内存时,操作系统会自动减小Cache的大小
                       如果cache占用的内存过多了,影响正常运行程序需要的内存,那么会释放掉一部分cache内存,但是总量会保持一个很高的值,所以,linux总是能最大限度的使用内存,就算加到16G,32G内存,也会随着不断的IO操作,内存的free值会慢慢减少到只有几M,想要内存不发生这种情况,只有一个办法:把内存加到比硬盘大。

       在linux下,可通过命令cat /proc/meminfo和free -m查看buffer cache的内存使用情况。

二、Buffer cache的功能详解
在从外存的一页到内存的一页的映射过程中,page cache与buffer cache、swap cache共同实现了高速缓存功能,以下是其简单映射图,

外存的一页(分解为几块,可能不连续)
|
|
物理磁盘的磁盘块
|
|
内存的buffer Cache
|
|
内存的一页(由一个页框划分的几个连续buffer cache构成)
|
|
页高缓系统

在这个过程中,物理文件系统与Buffer Cache交互,负责在外围存储设备和Buffer Cache 之间交换数据。
由于bcache位于物理文件系统和块设备驱动程序之间,因此,当物理文件系统需要从块设备上读取数据时,它首先试图从bcache中去读。如果命中,则内核就不必在去访问慢速的块设备。否则如果命中失败,也即数据不在bcache中,则内核从块设备上读取相应的数据块,并将其在bcache中缓存起来,以备下次访问之用。
类似地,但物理文件系统需要向块设备上写数据时,也是先将数据写到相应的缓冲区中,并将这个缓冲区标记为脏(dirty),然后在将来的某些时候将buffer cache中的数据真正地回写到块设备上,或者将该缓冲区直接丢弃。从而实现减少磁盘写操作的频率

三、Buffer Cache的数据结构
  1、缓冲区头部对象buffer_head
  每一个缓冲区都有一个缓冲区头部来唯一地标识与描述该缓冲区。Linux通过数据结构buffer_head来定义缓冲区头部。如下所示(include/linux/fs.h)

struct buffer_head {
/* First cache line: */
struct buffer_head *b_next; /* Hash queue list */
unsigned long b_blocknr; /* block number */
unsigned short b_size; /* block size */
unsigned short b_list; /* List that this buffer appears */
kdev_t b_dev; /* device (B_FREE = free) */

atomic_t b_count; /* users using this block */
kdev_t b_rdev; /* Real device */
unsigned long b_state; /* buffer state bitmap (see above) */
unsigned long b_flushtime; /* Time when (dirty) buffer should be written */

struct buffer_head *b_next_free;/* lru/free list linkage */
struct buffer_head *b_prev_free;/* doubly linked list of buffers */
struct buffer_head *b_this_page;/* circular list of buffers in one page */
struct buffer_head *b_reqnext; /* request queue */

struct buffer_head **b_pprev; /* doubly linked list of hash-queue */
char * b_data; /* pointer to data block (512 byte) */
struct page *b_page; /* the page this bh is mapped to */
void (*b_end_io)(struct buffer_head *bh, int uptodate); /* I/O completion */
void *b_private; /* reserved for b_end_io */

unsigned long b_rsector; /* Real buffer location on disk */
wait_queue_head_t b_wait;

struct inode * b_inode;
struct list_head b_inode_buffers; /* doubly linked list of inode dirty buffers */
};
各字段的含义如下:
1b_next指针:指向哈希链表中的下一个buffer_head对象。
2.b_blocknr:本缓冲区对应的块号(block number)。
3.b_size:以字节计掉的块长度。合法值为:512、1024、2048、4096、8192、16384和32768。
4.b_list:记录这个缓冲区应该出现在哪个链表上。
5.d_dev:缓冲区对应的块所在的块设备标识符(对于位于free_list链表中的缓冲区,b_dev=B_FREE)。
6.b_count:本缓冲区的引用计数。
7.b_rdev:缓冲区对应的块所在的块设备的「真实」标识符。
8.b_state:缓冲区的状态,共有6种:
/* bh state bits */
#define BH_Uptodate 0 /* 1 if the buffer contains valid data */
#define BH_Dirty 1 /* 1 if the buffer is dirty */
#define BH_Lock 2 /* 1 if the buffer is locked */
#define BH_Req 3 /* 0 if the buffer has been invalidated */
#define BH_Mapped 4 /* 1 if the buffer has a disk mapping */
#define BH_New 5 /* 1 if the buffer is new and not yet written out */
#define BH_Protected 6 /* 1 if the buffer is protected */
9.b_flushtime:脏缓冲区必须被回写到磁盘的最后期限值。
10.b_next_free指针:指向lru/free/unused链表中的下一个缓冲区头部对象。
11b_prev_free指针:指向lru/free/unused链表中的前一个缓冲区头部对象。
12b_this_page指针:指向同属一个物理页帧的下一个缓冲区的相应缓冲区头部对象。同属一个物理页帧的所有缓冲区通过这个指针成员链接成一个单向循环链表。
13b_reqnext指针:用于块设备驱动程序的请求链表。
14b_pprev:哈希链表的后向指针。
15b_data指针:指向缓冲区数据块的指针。
16b_page指针:指向缓冲区所在物理页帧的page结构。
17b_rsector:实际设备中原始扇区的个数。
18b_wait:等待这个缓冲区的等待队列。
19b_inode指针:如果缓冲区属于某个索引节点,则这个指针指向所属的inode对象。
20b_inode_buffers指针:如果缓冲区为脏,且又属于某个索引节点,那么就通过这个指针链入inode的i_dirty_buffers链表中。

缓冲区头部对象buffer_head可以被看作是缓冲区的描述符,因此,对bcache中的缓冲区的管理就集中在如何高效地组织处于各种状态下的buffer_head对象上。

  2、buffer_head对象的SLAB分配器缓存
  缓冲区头部对象buffer_head本身有一个叫做bh__cachep的slab分配器缓存。因此对buffer_head对象的分配与销毁都要通过kmem_cache_alloc()函数和kmem_cache_free()函数来进行。
  注意不要把bh_cachep SLAB分配器缓存和缓冲区本身相混淆。前者只是buffer_head对象所使用的内存高速缓存,并不与块设备打交道,而仅仅是一种有效管理buffer_head对象所占用内存的方式。后者则是块设备中的数据块所使用的内存高速缓存。但是这二者又是相互关联的,也即缓冲区缓存的实现是以bh_cachep SLAB分配器缓存为基础的。而我们这里所说的bcache机制包括缓冲区头部和缓冲区本身这两个方面的概念。
  bh_cachep定义在fs/dcache.c文件中,并在函数vfs_caches_init()中被初始化,也即通过调用kmem_cache_create()函数来创建bh_cachep这个SLAB分配器缓存。
  注:函数vfs_caches_init()的工作就是调用kmem_cache_create()函数来为VFS创建各种SLAB分配器缓存,包括:names_cachep、filp_cachep、dquot_cachep和bh_cachep等四个SLAB分配器缓存。

3、bcache中的缓冲区头部对象链表
  一个缓冲区头部对象buffer_head总是处于以下四种状态之一:
    1未使用(unused)状态:该对象是可用的,但是其b_data指针为NULL,也即这个缓冲区头部没有和一个缓冲区相关联。
    2空闲(free)状态:其b_data指针指向一个空闲状态下的缓冲区(也即该缓冲区没有具体对应块设备中哪个数据块);而b_dev域值为B_FREE(值为0xffff)。
    3正在使用(inuse)状态:其b_data指针指向一个有效的、正在使用中的缓冲区,而b_dev域则指明了相应的块设备标识符,b_blocknr域则指明了缓冲区所对应的块号。
    4异步(async)状态:其b_data域指向一个用来实现page I/O操作的临时缓冲区。
    
  为了有效地管理处于上述这些不同状态下的缓冲区头部对象,bcache机制采用了各种链表来组织这些对象(这一点,bcache机制与VFS的其它cache机制是相同的):
    1哈希链表:所有buffer_head对象都通过其b_next与b_pprev两个指针域链入哈希链表中,从而可以加快对buffer_head对象的查找(lookup)。
    2最近最少使用链表lru_list:每个处在inuse状态下的buffer_head对象都通过b_next_free和b_prev_free这两个指针链入某一个lru_list链表中。
    3空闲链表free_list:每一个处于free状态下的buffer_head对象都根据它所关联的空闲缓冲区的大小链入某个free_list链表中(也是通过b_next_free和b_prev_free这两个指针)。
    4未使用链表unused_list:所有处于unused状态下的buffer_head对象都通过指针域b_next_free和b_prev_free链入unused_list链表中。
    5inode对象的脏缓冲区链表i_dirty_buffers:如果一个脏缓冲区有相关联的inode对象的话,那么他就通过其b_inode_buffers指针域链入其所属的inode对象的i_dirty_buffers链表中。
    (更详细的介绍请见参考资料二)

四、buffer cache的回写
  有些是直接写(write-through):数据将被立刻写入磁盘,当然,数据也被放入缓存中。如果写操作是在以后做的,那么该缓存被称为后台写(write-back)。后台写比直接写更有效,但也容易出错:如果机器崩溃,或者突然掉电,缓冲中改变过的数据就被丢失了。如果仍未被写入的数据含有重要的薄记信息,这甚至可能意味着文件系统(如果有的话)已不完整。
  针对以上的原因,出现了很多的日志文件系统,数据在缓冲区修改后,同时会被文件系统记录修改信息,这样即使此时系统掉电,系统重启后会首先从日志记录中恢复数据,保证数据不丢失。当然这些问题不再本文的叙述范围。
  由于上述原因,在使用适当的关闭过程之前,绝对不要关掉电源,sync命令可以清空(flushes)缓冲,也即,强迫所有未被写的数据写入磁盘,可用以确定所有的写操作都已完成。在传统的 UNIX系统中,有一个叫做update(kupdate)的程序运行于后台,每隔30秒做一次sync操作,因此通常无需手工使用sync命令了。Linux另外有一个后台程序,bdflush,这个程序执行更频繁的但不是全面的同步操作,以避免有时sync的大量磁盘I/O操作所带来的磁盘的突然冻结。

五、Buffer Cache和Page Cache及其它
  page不会同时存在于buffer cache和page cache。add_page_to_hash_queue将此思想显露无余。buffer_head 定义在fs.h,和文件系统有着更为紧密的关系。从文件读写角度看buffer cache缓存文件系统的管理信息像root entry, inode等,而page cache缓存文件的内容。
  注意函数block_read_full_page,虽然位于buffer.c,但并没有使用buffer cache. 但是确实使用了buffer:只是再指定page上创建buffer提交底层驱动读取文件内容.这个流程有两个值得注意的地方:
  一是普通file的read通过page cache进行
  二是page cache读取的时候不和buffer cache进行同步
  三是page cache的确使用了buffer,不过注意,buffer 不是buffer cache。

  2.4的改进:page cache和buffer cache耦合得更好了。在2.2里,磁盘文件的读使用page cache,而写绕过page cache,直接使用buffer cache,因此带来了同步的问题:写完之后必须使用update_vm_cache()更新可能有的page cache。2.4中page cache做了比较大的改进,文件可以通过page cache直接写了,page cache优先使用high memory。而且,2.4引入了新的对象:file address space,它包含用来读写一整页数据的方法。这些方法考虑到了inode的更新、page cache处理和临时buffer的使用。page cache和buffer cache的同步问题就消除了。原来使用inode+offset查找page cache变成通过file address space+offset;原来struct page 中的inode成员被address_space类型的mapping成员取代。这个改进还使得匿名内存的共享成为可能(这个在2.2很难实现,许多讨论过)。

free 命令详解

  free 命令相对于top 提供了更简洁的查看系统内存使用情况:

  $ free

  # free
   total used free shared buffers cached
  Mem: 255988 231704 24284 0 6432 139292
  -/+ buffers/cache: 85980 170008
  Swap: 746980 0 746980

   可用选项:
     -b 以Byte为单位显示
     -k 以KB为单位显示 【默认的】
     -m 以MB为单位显示
     -s delay:显示每隔多少秒数来显示一次内存使用情况
     -t 显示内存总和列
     -o 不显示缓冲区调节列


  Mem:表示物理内存统计

  -/+ buffers/cached:表示物理内存的缓存统计

  Swap:表示硬盘上交换分区的使用情况,这里我们不去关心。

  系统的总物理内存:255268Kb(256M),但系统当前真正可用的内存b并不是第一行free 标记的 16936Kb,它仅代表未被分配的内存。

  我们使用total1、used1、free1、used2、free2 等名称来代表上面统计数据的各值,1、2 分别代表第一行和第二行的数据。

  total1:表示物理内存总量。
  used1:表示总计分配给缓存(包含buffers 与cache )使用的数量,但其中可能部分缓存并未实际使用。
  free1:未被分配的内存。
  shared1:共享内存,一般系统不会用到,这里也不讨论。
  buffers1:系统分配但未被使用的buffers 数量。
  cached1:系统分配但未被使用的cache 数量。buffer 与cache 的区别见后面。
  used2:实际使用的buffers 与cache 总量,也是实际使用的内存总量。
  free2:未被使用的buffers 与cache 和未被分配的内存之和,这就是系统当前实际可用内存

  可以整理出如下等式:

  total1 = used1 + free1total1 = used2 + free2used1 = buffers1 + cached1 + used2free2 = buffers1 + cached1 + free1

  buffer 与cache 的区别

  A buffer is something that has yet to be "written" to disk. A cache is something that has been "read" from the disk and stored for later use.

更详细的解释参考:Difference Between Buffer and Cache

摘自:http://space.itpub.net/?uid-33600-action-viewspace-itemid-266415

内存文件系统【Linux下使用内存文件系统】

这里主要介绍了内存文件系统的两种形式:ramfs tmpfs

在Linux中可以将一部分内存当作分区来使用,我们称之为RamDisk。对于一些经常被访问的文件,而它们又不会被更改,可以将它们通过 RamDisk放在内存中,即可明显地提高系统的性能。当然你的内存可要足够大了。RamDisk有两种,一种可以格式化,加载,在Linux内核 2.0/2.2就已经支持,其不足之处是大小固定。另一种是内核2.4才支持的,通过Ramfs或者tmpfs来实现,它们不能被格式化,但是用起来灵 活,其大小随所需要的空间而增加或减少。这里主要介绍一下Ramfs和Tmpfs。

Ramfs顾名思义是内存文件系统,它工作于虚拟 文件系统(VFS)层。不能格式化,可以创建多个,在创建时可以指定其最大能使用的内存大小。如果你的Linux已经将Ramfs编译进内核,你就可以很 容易地使用Ramfs了。创建一个目录,加载Ramfs到该目录即可。

# mkdir -p /RAM1
# mount -t ramfs none /RAM1

缺省情况下,Ramfs被限制最多可使用内存大小的一半。可以通过maxsize(以kbyte为单位)选项来改变。

QUOTE:
# mkdir -p /RAM1
# mount -t ramfs none /RAM1 -o maxsize=10000
以上即创建了一个限定了最大使用内存大小为10M的ramdisk。

Tmpfs 是一个虚拟内存文件系统,它不同于传统的用块设备形式来实现的ramdisk,也不同于针对物理内存的Ramfs。Tmpfs可以使用物理内存,也可以使 用交换分区。在Linux内核中,虚拟内存资源由物理内存(RAM)和交换分区组成,这些资源是由内核中的虚拟内存子系统来负责分配和管理。Tmpfs就 是和虚拟内存子系统来"打交道"的,它向虚拟内存子系统请求页来存储文件,它同Linux的其它请求页的部分一样,不知道分配给自己的页是在内存中还是在 交换分区中。Tmpfs同Ramfs一样,其大小也不是固定的,而是随着所需要的空间而动态的增减。使用tmpfs,首先你编译内核时得选择"虚拟内存文 件系统支持(Virtual memory filesystem support)" ,然后就可以加载tmpfs文件系统了。

# mkdir -p /mnt/tmpfs
# mount tmpfs /mnt/tmpfs -t tmpfs

为了防止tmpfs使用过多的内存资源而造成系统的性能下降或死机,可以在加载时指定tmpfs文件系统大小的最大限制。

# mount tmpfs /mnt/tmpfs -t tmpfs -o size=32m

以上创建的tmpfs文件系统就规定了其最大的大小为32M。不管是使用ramfs还是tmpfs,必须明白的是,一旦系统重启,它们中的内容将会丢失。所以那些东西可以放在内存文件系统中得根据系统的具体情况而定。

再补充一下:ramfs只会在物理内存中被创建,而tmpfs可能在物理内存中创建,也可能在交换分区中被创建。对于想利用内存的高速IO来提高效能的应用,最好是使用ramfs。对于只是想存放临时缓存的应用,最好是用tmpfs,以提前内存的利用率。

内存文件系统【FreeBSD下的内存文件系统】

FreeBSD下的内存文件系统

大多数操作系统,包括FreeBSD,通常使用磁盘来保存需要存储的数据。而操作系统采用文件的形式来保存数据,因此操作系统在磁盘上存储数据需要按照一定的格式进行,以便系统能够正确存储和访问文件,数据在磁盘上的组织格式被称为文件系统,不同的操作系统通常使用不同的数据组织格式,就是说使用不同的文件系统,例如FreeBSD使用UFS,而Linux使用Ext2FS等等。UFS是最古老和标准的Unix文件系统,但FreeBSD下对其进行了改进,主要目的是改善性能,改进后的文件系统也被称为FFS。

由于文件系统已经成为了操作系统访问外部磁盘数据的标准形式,操作系统很少直接访问磁盘获取数据。由于数据存储在实际应用中的重要意义,文件系统已经成为操作系统最基本的元素之一。进一步,多个操作系统可以通过同样的文件系统访问外部磁盘,而同一个操作系统也可以通过不同的文件系统访问不同的外部磁盘设备。这样一来,文件系统就成为了界于操作系统和外部磁盘设备之间的一个独立层次。

正是由于文件系统已经成为了独立的一个抽象层,因此可以在这个层次进行更为复杂的处理,例如不让文件系统从磁盘设备设备上读取数据,而是从网络上读取数据,就形成了网络文件系统,从内存中读取数据就形成了内存文件系统,对读取的数据进行加解密处理,就形成了加密文件系统,等等。

虚拟磁盘和内存文件系统

虽然目前磁盘的容量、速度和可靠性基本上能满足绝大多数应用系统的要求,但是在某些情况下,使用磁盘存储数据仍然存在一些问题。一个例子是在嵌入式系统中,系统通常没有磁盘,数据通常存储在各种不可擦写或可擦写型半导体芯片中。另一个常遇到的例子是应用系统对于数据访问要求特别高的性能,由于磁盘是一种机械设备,读写的性能总是有限的,不能满足应用系统的需要。

在这些例子中,在面对需要解决的问题的时候,通常有一个隐含前提,就是不改动操作系统和应用程序本身。如果可以改动系统,那么,人们就可以针对具体的需要设计另外一套完整的系统,上述问题事实上也就并不存在了。但是这种做法并不现实,因为这将意味着将全部操作系统和应用系统都推倒重来。因此,为了解决这些极端的需求,最简单的方法是在内存中分配一个区域作为文件系统的数据存储区,而不是使用磁盘作为存储设备,这样既能够满足操作系统对文件系统的需求,也能够满足应用系统的特殊需要。

使用内存作为文件系统基本上有两种不同的选择方式,最简单的方式是将内存中的一个区域模拟一个磁盘分区,然后就可以在这个虚拟磁盘上按照现有的文件系统组织数据,因此就需要初始化文件系统、装载与卸载等标准文件系统操作。另一种方法为重新设计一套全新的文件系统,其中并不包含任何磁盘的概念,但在系统中表现为一个标准文件系统。明显的,重新设计一套文件系统需要更多的工作量,因此,绝大多数情况下,人们使用第一种虚拟磁盘的方法。但是,现有的文件系统,如UFS等,都是基于磁盘设备而设计的,因此很多概念,比如按磁盘块读取数据、缓冲、碎片等等,都是针对磁盘设备提出的,理论上基于内存的存储不需要这些概念,因而也不会出现这些概念需要解决的一些问题。

由于内存文件系统是使用内存来模拟磁盘操作,因此数据都是在内存之间传输,就可以得到比较高的读写性能。当然,使用内存文件系统,一旦系统重新启动,所有的内容也就不再存在了,因此只能用来保存临时性的数据。也是由于是使用内存来保存数据,缓冲实质上没有任何意义,传统文件系统中的异步”async”和同步”sync”这两种概念的意义也不大了。

虽然从本质上讲,内存文件系统根本不需要缓冲,直接访问就能达到最好的效率,但是很难做到这一点,尤其是由于目前都还是使用内存来模拟一个磁盘设备的情况,内存文件系统事实上还是经过了缓冲。从这个地方,也可以看出目前使用的内存文件系统的弊病,内存文件系统本身占据了一份内存,磁盘缓冲又会占据一份内存,这样就导致了内存的浪费。在系统有交换分区存在的条件下,一旦系统内存紧张,该文件系统中的有关数据也会被交换到具体的交换设备上,同样避免不了对磁盘的物理访问,达不到提高性能的目的。而且一旦包括交换空间在内的所有虚拟内存用光,系统就无法正常提供服务了,从而影响系统的稳定性。

试图使内存文件系统绕过磁盘缓冲其实并不容易,这是因为在目前的操作系统中,磁盘是非常重要的一部分。非常重要的虚拟内存概念就是使用磁盘设备作为交换设备模拟内存,而磁盘缓冲而是通过内存来缓冲磁盘数据,虚拟内存、磁盘缓冲就是操作系统内存管理中的最基本元素,如何处理这两个部分,也是影响系统性能的最重要的因素。文件系统实质上是建立在操作系统的内存管理部分之上的,因此绕过这一部分,需要更困难的内核工作。

因此,对于高负载的服务器,使用内存文件系统实际上得不偿失,在系统内存很快用光的情况下,操作系统将进行磁盘交换,导致系统性能严重下降,这比起直接使用磁盘文件系统更为糟糕。事实上,在高负载的服务器环境下,允许系统使用更多的内存来缓冲磁盘数据,更有效的发挥系统的磁盘缓冲能力,在实际使用中更为有效。

使用MFS

FreeBSD下最基本的内存文件系统为MFS(Memory File System)文件系统,它是直接从虚拟内存中为文件系统申请空间。虽然它命名为MFS,实质上它还是使用的标准UFS的数据组织格式,仍然有扇区、磁盘块等基本概念,但是为了使用方便,它没有创建可以被直接访问的虚拟磁盘设备。实际上MFS是一个不完整的虚拟磁盘系统,由于它没有虚拟磁盘设备,因此导致在一些情况下它不能很方便的应用。

使用MFS需要内核中的”options MFS”支持,这个选项实质上是一个标准选项,在缺省情况下的FreeBSD内核都支持,因此一般不需要重新定制内核。然后就可以使用mount_mfs来安装内存文件系统,或者在标准mount命令中指定mfs选项。

# mount_mfs -s 131072 /dev/da0s1b /tmp

执行这个命令之后,mount_mfs就从虚拟内存中申请131072个扇区大小的内存,用来作为MFS文件系统的存储区域,并将该文件系统安装到/tmp目录下。这里使用/dev/da0s1b作为设备文件参数,这个磁盘分区为一个交换分区,它并不是实际使用的磁盘设备或虚拟磁盘,它的基本目的是用来满足mount_mfs的参数需要。即使系统中有多个交换设备,这也并不意味着MFS就只会交换到这个指定设备上,虚拟内存按照自己的规则分配物理内存或交换空间。

当然,使用交换设备作为参数事实上也起到了一些额外的作用,因为对于标准文件系统来讲,必须通过初始化的过程确定文件系统的组织格式,而MFS不需要独立的初始化过程,在mount_mfs操作的时候就同时执行了初始化,因而mount_mfs可以从这个设备文件中读取一些初始化相关的参数信息,例如每个扇区大小等,来初始化MFS文件系统。通常扇区尺寸为512字节,因此该文件系统总大小为64M。

这里就可以看出,基本的MFS是不存在虚拟磁盘设备的,mount_mfs直接申请内存并用作文件系统,而在mount命令中使用的设备参数为交换设备而非虚拟磁盘设备。一些情况下希望操作虚拟磁盘设备,那么使用MFS就不方便了。

使用vn伪设备

MFS是通过一个独立的文件系统来达到内存文件系统的目的,伪设备VN就是通过另一种方式来达到这个目的,它直接模拟一个虚拟的磁盘设备,那么在这个虚拟磁盘设备中可以应用各种不同的文件系统来保存数据。VN设备需要内核支持"pseudo-device vn"配置和/dev目录下的设备文件vn0、vn0c等,这通常不是缺省配置,需要用户重新定制内核。

VN设备主要使用文件作为虚拟磁盘的存储空间,例如将光盘的镜像文件用作虚拟光盘设备,将软盘的镜像文件作为虚拟软盘设备等等。当然模拟是有一定限度的,主要用来模拟文件系统,例如虚拟光盘设备上就没有音轨数据,无法作为CD播放等等。

显然使用内存保存虚拟磁盘数据,与使用文件相比甚至更为简单。因此,VN设备也支持使用内存来模拟一个虚拟磁盘。VN设备需要使用vnconfig程序来控制虚拟磁盘设备,那么为指定虚拟磁盘磁盘申请内存,并配置该虚拟磁盘的操作为:

# vnconfig -s 131072 /dev/vn0c

这里使用-s参数指明申请内存空间的大小,而vn0c为空闲的虚拟磁盘设备。配置好了虚拟磁盘之后,就可以使用标准的磁盘操作命令对磁盘进行操作,包括文件系统的初始化。对于虚拟磁盘设备来讲,一般不需要分区操作,而是直接进行文件系统操作,事实上虚拟磁盘通常也没有分区的概念,fdisk命令也不识别虚拟磁盘,可以将虚拟磁盘设备当作一个完整的分区设备。这是因为在Unix下本来是没有磁盘分区的概念的,这个概念是DOS/PC概念,因此FreeBSD对磁盘分区的支持限于可能存在其他系统的物理磁盘,对于只用于Unix的虚拟磁盘,就不需要这个概念了。

# disklabel -r -w /dev/vn0c auto

# newfs /dev/vn0c

# mount /dev/vn0c /tmp

由于使用VN设备比起MFS来讲要多一个创建虚拟磁盘设备的过程,因此使用vnconfig就与使用mount_mfs不同,要略微麻烦一些,除了需要经历vnconfig配置虚拟磁盘之外,还需要初始化磁盘设备、创建文件系统等步骤。

显然,由于创建了虚拟磁盘设备,在这里就不再是裸的MFS系统,而是一个更为完善的虚拟磁盘系统。显然,这里就不需要MFS的帮助,而在newfs和mount时直接使用UFS文件系统。理论上可以使用各种不同的文件类型格式,并不限于是UFS。

内存磁盘设备md

使用MFS系统,就可以最方便快捷的建立内存文件系统,使用vn设备,就可以建立内存文件系统相关的虚拟磁盘设备,基本上,这两个内存文件系统将满足绝大多数应用系统的需要。然而,一个非常重要的问题仍然存在,就是这些内存文件系统都是在系统启动之后,通过相应的配置命令进行配置的,而在一些情况下,需要在系统启动或启动之前,就配置好内存文件系统。

这种在系统启动之前要求配置好内存文件系统的例子之一就是系统安装程序,因为安装系统通常都是使用光盘或软盘启动,光盘或软盘作为系统的根文件系统当然是可行的,但总存在种种限制,例如软盘的访问速度和可靠性限制,光盘的只读限制等等。因此,目前的FreeBSD的系统安装程序,是使用内存文件系统作为安装系统的根文件系统,而不是试图将软盘或光盘作为安装系统的根文件系统。在这种情况下,通常使用一个独立的系统镜像文件,在启动之前载入内存,作为内存文件系统的初始数据来配置内存文件系统。

为了达到这个目的,就需要使用系统中的伪设备md,这需要相应的内核支持"pseudo-device md",这个选项通常需要重新定制内核。此后,还需要在/dev目录下创建相应的设备文件md0和md0c。这样使用新内核重新启动之后,就可以用使用普通磁盘一样的方法来使用它了,而不需要任何配置过程。

# disklabel -r -w /dev/md0c auto

# newfs /dev/md0c

# mount /dev/md0c /tmp

这里不需要使用任何配置程序配置虚拟磁盘设备,因为在启动过程中它就被自动配置了,内核为设备自动申请必要的内存空间。需要注意的是,使用MD设备并没有指定磁盘的大小,因为预先保留的md磁盘的大小是在编译内核时就确定的,缺省大小为20000个扇区。如果要更改内核为MD设备分配的空间大小,就需要在定制内核时改变设置选项”MD_NSECT”的值,并重新编译内核。显然,这样做显然比较麻烦,也使得它的实际用处不大。

但当MD设备用在安装系统的时候,作为最初启动的虚拟磁盘需要载入一个预先配置好的磁盘镜像文件,这个时候虚拟磁盘的大小就是由这个磁盘镜像文件决定的,而不再是MD_NSECT设置的值。正是由于MD设备在启动过程中配置,因而灵活性不足,就使得MD设备主要用在安装系统中。

启动镜像设置

对于系统安装程序,或者一些嵌入式系统来讲,存储数据的物理设备无法很方便的作为文件系统存在,例如存储设备为不可擦写的ROM或者具备一定擦写寿命的Flash中,这些设备如果用作文件系统就有各种各样的限制,此时就需要使用内存文件系统作为辅助,例如使用内存文件系统作为根文件系统,或者作为临时文件系统等等。

但是由于内存文件系统是使用不可长期保存的RAM存储器保存数据,系统重新启动或断电后其中保存的数据就不再存在,因此每次启动之后虚拟磁盘中的数据都是随机的,需要重新进行初始化操作。也可以提供一种手段为最初的虚拟磁盘提供初始数据,通常这通过使用镜像文件的方法来完成。

使用伪设备MD,就可以将一个预先准备好的文件作为md设备的镜像数据,这样MD设备一旦创建就已经具备了必要的数据,而系统启动之后立即可以访问已经具备数据的虚拟磁盘了。通过这样的操作,就可以使用虚拟磁盘文件系统作为根文件系统,启动其中的系统安装程序。

因此,这个时候就需要为MD设备准备初始镜像文件,最直接的方法是首先用确定的大小创建MD设备,初始化文件系统,安装上文件系统并复制必要的数据,然后在卸载文件系统,使用dd命令直接操作虚拟磁盘设备,将数据复制到一个镜像文件中。但是由于MD设备的大小比较不容易改变,因此这种方法并不灵活。此外,由于MD设备被作为一个虚拟的物理磁盘被系统处理,系统对它的处理事实上是和真实物理磁盘设备的处理方法也是一样的,因此也可以使用物理磁盘,创建文件系统并复制其镜像的方法来获得镜像数据。

使用虚拟磁盘MD和物理磁盘都可以得到镜像文件,但是这两种方法都不是很灵活,最好的方法是可以直接修改镜像文件本身。事实上VN设备正是用作这个处理任务,它能使用镜像文件作为虚拟磁盘的存储区域,使用VN设备创建并修改镜像文件的数据是非常适合的。因此在大小一致的条件下,就可以直接将VN设备的镜像文件复制到MD设备上,然后将MD设备安装到系统中,就可以访问到具体数据。

因此,使用VN设备预先定制好MD设备使用的镜像文件是最常用、最方便的方法。系统载入镜像文件的过程应该在启动之前完成,以便系统在启动过程中能够配置好该MD设备。事实上,镜像文件是由Boot Loader载入的,作为MD设备的缺省数据。当然,另一种选择是直接将镜像文件写入内核文件中,使得镜像数据和内核一起载入。将镜像文件写入内核的方式需要改动内核,并且写入之后就不容易改变镜像文件中的数据,因此,目前这种方式很少被用到。

为了将镜像文件写入内核,需要设置内核选项MD_ROOT_SIZE,需要指定它的尺寸大于镜像文件的尺寸,以便系统在内核中保留出大于镜像文件的自由空间,以使得写入的数据不至于覆盖内核中有用的数据。这个参数和MD_NSECT是不同的,但它也为一个虚拟磁盘预保留了空间。如果是使用Boot Loader来载入镜像文件,就不能设置这个选项,因为这将导致系统在启动时初始化多个虚拟磁盘,而只有第一个虚拟磁盘md0才是可以启动的。

当然,一个能够将MD设备作为启动根文件系统的内核,除了标准的md和MFS选项之外,还需要"options MD_ROOT"的设置选项,以保证内核搜索MD设备的作为根文件系统。这个设置也可以写作"MFS_ROOT",以便和早期的FreeBSD系统兼容,早期的FreeBSD系统没有使用md伪设备,而是使用第二种直接写入内核的MFS文件系统作为根文件系统。

几种不同方式的比较

无论是MFS,还是VN设备和MD设备,它们对数据的处理方式其实是非常类似的,MFS就是直接在内存中开辟一个UFS格式的区域,用作文件系统,这个区域其实就是一个虚拟磁盘镜像。而VN设备和MD设备是先申请内存空间,然后采用标准的文件系统工具进行处理,因此更为灵活。

最为重要的一点区别实际上是它们获得自由内存空间的方式不同,MFS和VN实际上是使用动态的方式申请虚拟内存,而md设备实际上是在系统启动之前已经分配完毕,是一种静态的方式,其实是通过内核申请空间的方式MALLOC分配的。这样就导致MFS和VN设备申请的内存是按照虚拟内存的方式进行处理,就是说它们是基于交换空间的,在物理内存不够的情况下将被自然的交换到磁盘设备中。而MD设备使用的内存是内核申请的,因而位于内核空间中,主要占用物理内存。

这两种不同的使用内存的方式,造成了这几种不同的内存文件系统的不同用途和使用限制,MFS和VN可以使用更多的交换空间,因而容量更大,使用更灵活,但在高负载的情况下由于系统交换,仍然会造成磁盘访问。虽然对于md设备,这种现象理论上不会发生,但md设备的大小是受到物理内存的限制的,占用的是宝贵的内核空间,因此主要用来处理比如启动镜像这样的情况,而很少用来处理其他任务。

除了这些文件系统之外,FreeBSD上事实上还有其他的一些内存文件系统,例如V9FS,这种文件系统的特征是一个纯粹的文件系统,没有涉及磁盘的那些扇区、块等概念等等,这些文件系统目前还不是很完善,也不是标准系统的一部分。

对于内存文件来讲,一些特色其实是非常有意义的,例如文件系统的压缩技术,由于它能够减少内存空间的大小,因此对于内存文件系统是非常有意义的,可以用于嵌入式系统等领域。虽然有人在这个方面曾经做过努力,但目前这种特性在FreeBSD下还不能直接得到。

FreeBSD 5.0中内存文件系统

当对这几种不同的文件系统进行分析比较之后,可以发现它们存在很多种共性,例如MFS和vn设备对于内存的使用方式是相同的,而vn设备和md设备由于都是虚拟磁盘,因此其内容是相同的,这也导致了可以使用vn设备为md设备创建镜像文件。因此,完全可以将这三种不同的使用内存文件系统的方式合并起来,使设置和操作更为简单易用。

事实上,之所以存在这几种不同的内存文件系统,源于FreeBSD的历史开发过程。最早的内存文件系统显然是MFS,但由于不存在虚拟磁盘,存在种种不统一和协调的地方,因此后来就设计了MD设备。VN设备则与此无关,它最初就是为了文件作为存储设备而设计的,但使用内存作为存储显然也十分直接和简单。

因此,在最新的FreeBSD 5.0版本中,这些内存文件系统的设置都统一起来,特别是将vn设备和md设备的功能都统一到新版本的伪设备md中。并且在FreeBSD 5.0下,设备的创建和内存的分配更为方便,不象在4.x之前,系统中的配置选项只能指定一定数量的虚拟磁盘设备(缺省是一个设备)。而且,由于FreeBSD 5.0使用了DEVFS特色,设备文件的创建是自动进行的,不再需要手工使用MAKEDEV命令创建设备文件入口。

例如,需要从虚拟内存中申请内存创建内存文件系统的时候,就需要执行md设备的控制程序mdconfig:

# mdconfig -a -t swap -s 30M

这就会在虚拟内存中申请30M空间,并创建虚拟磁盘,使用的虚拟设备为第一个md设备md0,如果系统中的md0设备已经被占用,那么mdconfig就依序向后寻找下一个空余的md设备,并创建它。由于mdconfig能自动创建新的设备,这样就解决了在内核配置文件指定伪设备数量的问题。

也可以使用-u指定使用的md伪设备的序号,例如下列命令将创建md10,并使用它作为虚拟磁盘设备:

# mdconfig -a -t swap -s 30M -u 10

上面的命令都是使用虚拟内存空间作为数据存储空间,是由swap参数指定的。同样,使用mdconfig也能从内核空间中创建虚拟磁盘,此时-t指定的存储类型参数为malloc,这告诉内核使用内核的MALLOC方法申请内存。

# mdconfig -a -t malloc -s 30M

这种方法就相当于老的md设备的申请内存的方法,但显然更为灵活,因为可以在具体使用过程中申请内存和设备,这是因为FreeBSD 5.0的内核允许更灵活的使用MALLOC内存申请方式。当然,一般还是主要使用swap申请虚拟空间的内存。

由于mdconfig和伪设备md将完全代替vnconfig和伪设备vn,那么使用mdconfig也能创建使用文件作为虚拟磁盘的与vn兼容的方式,这需要指定存储类型参数为vnode,并使用 -f指定具体的存储数据的物理文件名字。

# mdconfig -a -t vnode -f imagefile -s 30M

在使用mdconfig配置好虚拟磁盘之后,就可以使用disklabel、newfs、mount等管理虚拟磁盘。而在不需要这些虚拟磁盘的时候,就可以卸载相应的文件系统,并使用mdconfig删除指定的磁盘等。

# mdconfig -l

使用参数”-l”,则mdconfig列出系统中所有的虚拟磁盘设备。

# mdconfig -d -u 0

为了删除指定了磁盘,需要使用”-d"参数,而使用"-u 0”则指定删除序号为0的虚拟磁盘,即md0。

什么是UNIX系统

摘自:http://www.apuebook.com/index.html

        

  1. What is the difference between "UNIX System" and "UNIX system?"

When we speak of the UNIX System itself as an entity, we capitalize the ‘S’ in System. When we are speaking about a possible implementation of the UNIX System or a particular UNIX system, we use a lower-case ‘s’.

        

  1. What is the difference between Unix and UNIX?

The Unix operating system was developed at AT&T Bell Laboratories. When AT&T registered the name as a trademark, they capitalized the name to UNIX. Today the trademark is owned by The Open Group. For a system to call itself UNIX, it needs to meet certain criteria, pass conformance tests, and license the name.

        

  1. Is Mac OS X a UNIX system?

While Mac OS X resembles a UNIX system and provides a UNIX-compatible environment, it has not yet been formally certified as a UNIX system. On the other hand, if it looks like a duck, walks like a duck, and quacks like a duck, then it’s probably a duck.

        

  1. Is FreeBSD a UNIX system?

While FreeBSD resembles a UNIX system and provides a UNIX-compatible environment, it has not yet been formally certified as a UNIX system. On the other hand, if it looks like a duck, walks like a duck, and quacks like a duck, then it’s probably a duck.

        

  1. Is Linux a UNIX system?

While Linux resembles a UNIX system and provides a UNIX-compatible environment, it has not yet been formally certified as a UNIX system. On the other hand, if it looks like a duck, walks like a duck, and quacks like a duck, then it’s probably a duck.

        

  1. Is Solaris a UNIX system?

Yes, Solaris has been formally certified to be a UNIX system.

 

简单地用中文总结一下:Mac OS X    FreeBSD   Linux 都是类unix系统,但是没有正式地说法;Solaris确实是真正的unix系统

PHP版的ftok函数实现

从php手册中抄的,但是我也看过C版的ftok函数的实现,两个是一样的:

<?php
function ftok($pathname$proj_id
) {
   
$st = @stat($pathname
);
   if (!
$st
) {
       return –
1
;
   }
   
   
$key sprintf("%u", (($st[‘ino’] & 0xffff) | (($st[‘dev’] & 0xff) << 16) | (($proj_id 0xff) << 24
)));
   return 
$key
;
}

echo ftok($_SERVER["SCRIPT_FILENAME"], 250);
?>

注意里面影响ftok值的几个因素: 文件的inode 和dev

iostat 命令简介

iostat 命令报告cpu利用率磁盘利用率两项内容。

iostat -c 只查看cpu利用率

iostat -d 只查看磁盘利用率

iostat device 显示指定磁盘的利用率信息 如: iostat sda

iostat -p device 显示指定磁盘的各个分区的利用率信息 如: iostat -p sda 注意device是磁盘,不能是分区

iostat -x 显示磁盘利用率的更详细信息 注意:-x -p不能同时使用,-x -c同时使用也是没有意义的

iostat -k 以KB为单位显示磁盘统计信息

iostat -m 以MB为单位显示磁盘统计信息

iostat interval 即:隔inerval时间显示一次,如,iostat 2 隔两秒显示一次,直到ctrl+c 结束

iostat interval count 即:隔inerval时间显示一次,显示count 次数结束,如,iostat 2 6 隔2秒显示一次,显示6次结束

显示信息解释:

cpu信息:

avg-cpu: %user %nice %system %iowait %steal %idle
0.08 0.07 1.38 0.14 0.00 98.33

%user :cpu处于用户空间的时间

%nice :cpu花费在更改级别后的进程上的时间比

%system:cpu花费在执行内核代码上的时间比

%iowait: cpu花费在等待io上的时间比 该值太大说明io是瓶颈

%steal : ???

%idle : cpu的空闲时间比

磁盘信息:

Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn
sda 2.36 0.56 34.11 11801313 713114808
sda1 3.84 0.20 15.29 4147757 319673956
sda2 3.36 0.20 13.36 4242258 279425316

tps :
Indicate the number of transfers per second that were issued to the device. A transfer is an I/O
request to the device. Multiple logical requests can be combined into a single I/O request to the
device. A transfer is of indeterminate size.

# iostat -x 1 10
Linux 2.6.18-92.el5xen    02/03/2009

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           1.10    0.00    4.82   39.54    0.07   54.46

Device:         rrqm/s   wrqm/s   r/s   w/s   rsec/s   wsec/s avgrq-sz avgqu-sz   await  svctm  %util
sda               0.00     3.50  0.40  2.50     5.60    48.00    18.48     0.00    0.97   0.97   0.28
sdb               0.00     0.00  0.00  0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sdc               0.00     0.00  0.00  0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sdd               0.00     0.00  0.00  0.00     0.00     0.00     0.00     0.00    0.00   0.00   0.00
sde               0.00     0.10  0.30  0.20     2.40     2.40     9.60     0.00    1.60   1.60   0.08
sdf              17.40     0.50 102.00  0.20 12095.20     5.60   118.40     0.70    6.81   2.09  21.36
sdg             232.40     1.90 379.70  0.50 76451.20    19.20   201.13     4.94   13.78   2.45  93.16

rrqm/s:   每秒进行 merge 的读操作数目。即 delta(rmerge)/s
wrqm/s:  每秒进行 merge 的写操作数目。即 delta(wmerge)/s
r/s:           每秒完成的读 I/O 设备次数。即 delta(rio)/s
w/s:         每秒完成的写 I/O 设备次数。即 delta(wio)/s
rsec/s:    每秒读扇区数。即 delta(rsect)/s
wsec/s:  每秒写扇区数。即 delta(wsect)/s
rkB/s:      每秒读K字节数。是 rsect/s 的一半,因为每扇区大小为512字节。(需要计算)
wkB/s:    每秒写K字节数。是 wsect/s 的一半。(需要计算)
avgrq-sz: 平均每次设备I/O操作的数据大小 (扇区)。delta(rsect+wsect)/delta(rio+wio)
avgqu-sz: 平均I/O队列长度。即 delta(aveq)/s/1000 (因为aveq的单位为毫秒)。
await:    平均每次设备I/O操作的等待时间 (毫秒)。即 delta(ruse+wuse)/delta(rio+wio)
svctm:   平均每次设备I/O操作的服务时间 (毫秒)。即 delta(use)/delta(rio+wio)
%util:      一秒中有百分之多少的时间用于 I/O 操作,或者说一秒中有多少时间 I/O 队列是非空的。即 delta(use)/s/1000 (因为use的单位为毫秒)

如果 %util 接近 100%,说明产生的I/O请求太多,I/O系统已经满负荷,该磁盘
可能存在瓶颈。
idle小于70% IO压力就较大了,一般读取速度有较多的wait.

同时可以结合vmstat 查看查看b参数(等待资源的进程数)和wa参数(IO等待所占用的CPU时间的百分比,高过30%时IO压力高)

另外还可以参考
svctm 一般要小于 await (因为同时等待的请求的等待时间被重复计算了),svctm 的大小一般和磁盘性能有关,CPU/内存的负荷也会对其有影响,请求过多也会间接导致 svctm 的增加。await 的大小一般取决于服务时间(svctm) 以及 I/O 队列的长度和 I/O 请求的发出模式。如果 svctm 比较接近 await,说明 I/O 几乎没有等待时间;如果 await 远大于 svctm,说明 I/O 队列太长,应用得到的响应时间变慢,如果响应时间超过了用户可以容许的范围,这时可以考虑更换更快的磁盘,调整内核 elevator 算法,优化应用,或者升级 CPU。
队列长度(avgqu-sz)也可作为衡量系统 I/O 负荷的指标,但由于 avgqu-sz 是按照单位时间的平均值,所以不能反映瞬间的 I/O 洪水。


  别人一个不错的例子.(I/O 系统 vs. 超市排队)

举一个例子,我们在超市排队 checkout 时,怎么决定该去哪个交款台呢? 首当是看排的队人数,5个人总比20人要快吧? 除了数人头,我们也常常看看前面人购买的东西多少,如果前面有个采购了一星期食品的大妈,那么可以考虑换个队排了。还有就是收银员的速度了,如果碰上了连 钱都点不清楚的新手,那就有的等了。另外,时机也很重要,可能 5 分钟前还人满为患的收款台,现在已是人去楼空,这时候交款可是很爽啊,当然,前提是那过去的 5 分钟里所做的事情比排队要有意义 (不过我还没发现什么事情比排队还无聊的)。

I/O 系统也和超市排队有很多类似之处:

r/s+w/s 类似于交款人的总数
平均队列长度(avgqu-sz)类似于单位时间里平均排队人的个数
平均服务时间(svctm)类似于收银员的收款速度
平均等待时间(await)类似于平均每人的等待时间
平均I/O数据(avgrq-sz)类似于平均每人所买的东西多少
I/O 操作率 (%util)类似于收款台前有人排队的时间比例。

我们可以根据这些数据分析出 I/O 请求的模式,以及 I/O 的速度和响应时间。

下面是别人写的这个参数输出的分析

# iostat -x 1
avg-cpu: %user %nice %sys %idle
16.24 0.00 4.31 79.44
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s rkB/s wkB/s avgrq-sz avgqu-sz await svctm %util
/dev/cciss/c0d0
0.00 44.90 1.02 27.55 8.16 579.59 4.08 289.80 20.57 22.35 78.21 5.00 14.29
/dev/cciss/c0d0p1
0.00 44.90 1.02 27.55 8.16 579.59 4.08 289.80 20.57 22.35 78.21 5.00 14.29
/dev/cciss/c0d0p2
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

上面的 iostat 输出表明秒有 28.57 次设备 I/O 操作: 总IO(io)/s = r/s(读) +w/s(写) = 1.02+27.55 = 28.57 (次/秒) 其中写操作占了主体 (w:r = 27:1)。

平均每次设备 I/O 操作只需要 5ms 就可以完成,但每个 I/O 请求却需要等上 78ms,为什么? 因为发出的 I/O 请求太多 (每秒钟约 29 个),假设这些请求是同时发出的,那么平均等待时间可以这样计算:

平均等待时间 = 单个 I/O 服务时间 * ( 1 + 2 + … + 请求总数-1) / 请求总数

应用到上面的例子: 平均等待时间 = 5ms * (1+2+…+28)/29 = 70ms,和 iostat 给出的78ms 的平均等待时间很接近。这反过来表明 I/O 是同时发起的。

每秒发出的 I/O 请求很多 (约 29 个),平均队列却不长 (只有 2 个 左右),这表明这 29 个请求的到来并不均匀,大部分时间 I/O 是空闲的。

一秒中有 14.29% 的时间 I/O 队列中是有请求的,也就是说,85.71% 的时间里 I/O 系统无事可做,所有 29 个 I/O 请求都在142毫秒之内处理掉了。

delta(ruse+wuse)/delta(io) = await = 78.21 => delta(ruse+wuse)/s =78.21 * delta(io)/s = 78.21*28.57 = 2232.8,表明每秒内的I/O请求总共需要等待2232.8ms。所以平均队列长度应为 2232.8ms/1000ms = 2.23,而 iostat 给出的平均队列长度 (avgqu-sz) 却为 22.35,为什么?! 因为 iostat 中有 bug,avgqu-sz 值应为 2.23,而不是 22.35。

部分摘自:http://www.cnblogs.com/rootq/articles/1400115.html