kqueue介绍

这篇文章我从第一次接触kqueue到目前的理解,一直放在我的mempad中,最近有朋友对kqueue的一些疑问,所以我就把这个发出来。

首先需要简单的说明几个概念, struct event, kevent()和kqueue。

struct event就是kevent()操作的最基本的事件结构。
kevent() 是一个系统调用syscall,而kqueue是freebsd内核中的一个事件队列kernel queue。
kevent()是kqueue的用户界面,是对kqueue进行添加,删除操作的用户态的界面。

// ==========================================================

下面就重点介绍一下struct event和kevent()这两个开发者必须要了解的参数和API。

1. struct event 结构体中主要成员介绍

ident     – 标记事件的描述符, socketfd, filefd, signal
filter      – 事件的类型, 读事件:EVFILT_READ, 写事件:EVFILT_WRITE, 信号:EVFILT_SIGNAL
flags     – 事件的行为, 对kqueue的操作:
添加到kqueue中:EV_ADD, 从kqueue中删除:EV_DELETE, 这两种是主要的行为
一次性事件:EV_ONESHOT, 此事件是或操作, 指定了该事件, kevent()返回后, 事件会从kqueue中删除
更新事件: EV_CLEAR,此事件是或操作, 手册上的解释是,当事件通知给用户后,事件的状态会被重置。可以用在类似于epoll的ET模式,也可以用在描述符有时会出错的情况。
其他事件: EOF事件:EV_EOF, 错误事件:EV_ERROR(返回值)
fflags    –
data     –
udata   – 用户指定的数据
2. kevent() 各参数的说明

kq               – kqueue() 返回的唯一描述符, 标记着一个内核队列
changes       – 需要对kqueue进行修改的事件集合, 此参数就是kevent()对目前kqueue中的事件的操作,比如删除kqueue中已经存在的事件,或者向kqueue中添加新的事件,也就是说,kevent()通过此参数对kqueue的修改
nchanges     – 需要修改的事件的个数
events         – kevent()会把所有事件存储在events中
nevents       – kevent()需要知道存储空间有多大, == 0 : kevent()会立即返回
timeout        – 超时控制, = NULL:kevent()会一直等到有关注的事件发生; != NULL:kevent()会等待指定的时间
// ==========================================================

有几点需要说明的是 :

1) 指定EV_ADD|EV_ONESHOT或者EV_DELETE|EV_ONESHOT的行为, kevent()返回后, 会把事件从kqueue中删除;

2) 当事件类型指定为EVFILT_SIGNAL的时候, struct event 中data会返回此时信号发生了多少次
3) 如果 nevents == 0, kevent()会立即返回, 不会理会timeout指定的超时时间, 这是一种直接注册事件的方法.

原文链接: http://ray.bsdart.org/archives/304.raymond

FreeBSD下Vim的语法高亮与自动补全

FreeBSD下Vim的语法高亮与自动补全

vim 是与 emacs 齐名的超级编辑器(二者的使用哲学不同,没有高低贵贱之分)。我喜欢将 /usr/local/share/vim/vim73/colors/torte.vim 中的 ctermbg 设置为 NONE,这样 vim 就使用桌面背景显得“透明”(当然,这是假透明)。

vim 的功能十分强大,语法高亮和命令的自动补全更是不在话下。下面,我们逐一介绍它们。我们所用的 vim 版本在 7.0 以上。

语法高亮

下面,以矩阵计算工具 octave 和符号计算工具 maxima 为例,说明如何使编程语言在 vim 中语法高亮。

Octave 在 vim 中的语法高亮

我们怎么设置才能使得 vim 在编辑 foo.m 和 foo.oct 文件时做到语法高亮呢? 首先,找到文件 filetype.vim,打开它,看看后缀为 .m 和 .oct 是否被其他程序占用。 在我的 FreeBSD 中,.m 的后缀果真被 matlab 占用。matlab 没有 BSD 版本,我的机器上也没装 matlab 的 linux 版,所以干脆就把文件 filetype.vim 中的 matlab 替换为 octave。特别地,把 “*.oct” 加到 “*.m” 之后

" Octave or Objective C
au BufNewFile,BufRead *.m,*.oct         call s:FTm()

func! s:FTm()
  let n = 1
  while n < 10
    let line = getline(n)
    if line =~ ‘^\s*\(#\s*\(include\|import\)\>\|/\*\)’
      setf objc
      return
    endif
    if line =~ ‘^\s*%’
      setf octave
      return
    endif
    if line =~ ‘^\s*(\*’
      setf mma
      return
    endif
    let n = n + 1
  endwhile
  if exists("g:filetype_m")
    exe "setf " . g:filetype_m
  else
    setf octave
  endif
endfunc

把文件 octave.vim 拷贝到 syntax/matlab.vim 所在的目录。

maxima 在 vim 中的语法高亮

我希望所有后缀为 .mxm 的文件都被当做maxima文件语法高亮。

首先确保 maxima.vim 文件存在于 /usr/local/share/vim/vim72/syntax 目录下。编辑文件/usr/local/share/vim/vim72/filetype.vim,加入语句

" Maxima
au BufNewFile,BufRead *.mxm         setf maxima

命令的自动补全

到/usr/local/share/vim/vim72/autoload/目录下,看系统为哪些环境提供了命令的自动补全。也可以 locate ccomplete.vim,找到这个目录。

FreeBSD7.0下有ccomplete.vim、htmlcomplete.vim、……。然后,我们在 $HOME/.vimrc 中加入

"""""""""" 自动补全命令 """"""""""
autocmd Filetype c      set omnifunc=ccomplete#Complete
autocmd Filetype html   set omnifunc=htmlcomplete#CompleteTags
autocmd Filetype xml    set omnifunc=xmlcomplete#CompleteTags
autocmd Filetype python set omnifunc=pythoncomplete#CompleteTags
autocmd Filetype tex    set omnifunc=syntaxcomplete#Complete

.vimrc 的设置

$HOME/.vimrc 的普通设置,如下。

set nocompatible  "" not compatible with VI
set spell         "" highlight the typos
"" 在 vim 中查英文单词
nmap <C-\> : !sdcv -n <C-R>=expand("<cword>")<CR><CR>

"" Encodings and fonts
set encoding=utf-8
set fileencoding=utf-8
set fileencodings=ucs-bom,gb18030,gbk,gb2312,cp936
set termencoding=utf-8
set langmenu=zh_CN.UTF-8
language messages zh_CN.UTF-8
set guifontset=wenquanyi,-*-16-*-*-*

"" Tab and Backspace
set sw=2
set tabstop=4
set shiftwidth=4
set cindent
set smartindent
set autoindent
set backspace=indent,eol,start  "" set backspace

"" Display
set number        "" show line number
set ruler         "" always show current position
set cursorline    "" highlight the current line
set showcmd

"" Searching
set ignorecase    "" search setting
set incsearch
set hlsearch
set showmatch
set history=100
highlight Search term=reverse ctermbg=4 ctermfg=7

"" Syntax and color scheme
syntax enable
filetype plugin indent on
highlight Comment ctermfg=darkcyan
colorscheme torte

"""""""""" 自动补全命令 """"""""""
autocmd Filetype c      set omnifunc=ccomplete#Complete
autocmd Filetype html   set omnifunc=htmlcomplete#CompleteTags
autocmd Filetype xml    set omnifunc=xmlcomplete#CompleteTags
autocmd Filetype python set omnifunc=pythoncomplete#CompleteTags
autocmd Filetype tex    set omnifunc=syntaxcomplete#Complete

原文链接:http://wiki.freebsdchina.org/software/v/vim

FreeBSD使用固定设备节点名操作设备

使用固定设备节点名操作设备

eric.siroh(AT)gmail.com

FreeBSD-6之后,采用devfs管理设备节点,设备名称在设备联机时动态创建,增加了灵活性。但也带来另一些问题:一些外部设备,如USB、PCCard等设备并不总是在开机之前就连接到计算机,如果存在相同类型的设备,这些设备的在/dev的节点名称会因为设备连接到计算机的先后顺序而发生变化,这会给一些应用程序的设置造成一些不便。然而,正是因为devfs的灵活性,也带来很好的方法来支持这些外部设备使用固定设备节点名称。

这里通过两台USB接口打印机EPSON Stylus CX3700、Brother FAX-2820的设置来说明这一方法。

查看devfs基本配置

首先,查看/etc/devd.conf文件,确定有关的基本配置情况

#more /etc/devd.conf

options {
   # Each directory directive adds a directory the list of directories
   # that we scan for files.  Files are read-in in the order that they
   # are returned from readdir(3).  The rule-sets are combined to
   # create a DFA that’s used to match events to actions.
   directory "/etc/devd";
   directory "/usr/local/etc/devd";
   pid-file "/var/run/devd.pid";

   # Setup some shorthand for regex that we use later in the file.
   #XXX Yes, these are gross — imp
   set scsi-controller-regex
      "(aac|adv|adw|aha|ahb|ahc|ahd|aic|amd|amr|asr|bt|ciss|ct|dpt|\
      esp|ida|iir|ips|isp|mlx|mly|mpt|ncr|ncv|nsp|stg|sym|trm|wds)\
      [0-9]+";
};

通过这两行:

   directory "/etc/devd";
   directory "/usr/local/etc/devd";

得知用户定制配置文件目录为/etc/devd,/usr/local/etc/devd。如果没有相应的目录,自行建立就可以了。当然也可以自行修改,不过不建议修改。

获得设备信息

在编写配置文件之前,需要得到设备的必要参数。可以通过在前台运行调试模式的devd来查看。现在不要连接设备,运行

#/etc/rc.d/devd stop
#/sbin/devd -Dd

屏幕上会出现一些信息,表明devd已经运行了。这时把设备连接到计算机,然后再拔掉设备。这个过程中屏幕会有很多输出,只需要查看以Processing event开头信息。以下两行示例是U盘的插拔发生的信息。

Processing event ‘+umass0 vendor=0x1043 product=0x8012 devclass=0x00 devsubclass=0x00 release=0x0100 sernum="" intclass=0x08 intsubclass=0x06 at port=1 interface=0 vendor=0x1043 product=0x8012 devclass=0x00 devsubclass=0x00 release=0x0100 sernum="" intclass=0x08 intsubclass=0x06 on uhub1’
Processing event ‘-umass0 vendor=0x1043 product=0x8012 devclass=0x00 devsubclass=0x00 release=0x0100 sernum="" intclass=0x08 intsubclass=0x06 at port=1 interface=0 vendor=0x1043 product=0x8012 devclass=0x00 devsubclass=0x00 release=0x0100 sernum="" intclass=0x08 intsubclass=0x06 on uhub1’

umass0是devfs为U盘在/dev下自动生成的设备节点,+umass0表示umass0连接上计算机了,-umass0表示umass0设备被拔出。

我们需要得到设备信息主要是vendor,product,sernum三个参数。vendor是制造商的代码,product是设备型号代码,sernum是设备的序列好,这三个参数基本上应该可以确定唯一一台设备。

如果没有多于一台同一厂家同一型号(或同一系列,有点厂家设备虽然标识的型号不同,但是product值却是一样的)的设备,实际应用中vendor和product也就可以确定不同的设备了,这里还是使用sernum来增加确定性。在上面的示例中sernum为空,说明有的U盘没有序列号,没有序列号的U盘,不能用这三个参数来唯一确定。对于U盘可以通过glabel加标签的方法标识不同的U盘,会更方便一些。

获得必要的设备信息之后,就可以在控制台按Ctrl+C退出devd进程。

本例当中的两台USB打印机通过上述方法得到有关参数分别如下:

EPSON Stylus CX3700   product 0x0818   vendor 0x04b8   sernum L34020604060324210
Brother FAX-2820      product 0x0187   vendor 0x04f9   sernum 000H5J658204

编写配置文件

得到上述的这些信息之后,就可以动手编写配置文件了,配置文件应该保存在/etc/devd.conf文件中指定的目录下,本例中为/etc/devd/ulpt.conf,内容如下:

# EPSON Stylus CX3700 printer
# product  0x0818
# vendor   0x04b8
# sernum   L34020604060324210
attach 100 {                                              # 定义设备连接时的动作。100为优先级,用来控制
                                                          # 配置文件中该设备其他可能动作的先后次序
   device-name "ulpt[0-9]+";                              # 检测设备名称
   match "product"      "0x0818";                         # 检测product
   match "vendor"       "0x04b8";                         # 检测vendor
   match "sernum"       "L34020604060324210";             # 检测sernum
   action   "/bin/ln -sf /dev/$device-name /dev/epPRN";   # 如果该设备符合上面三个条件,
                                                          # 那么就在创建一个指向实际设备名的指定名称连接
};

# Brother FAX-2820 printer
# product  0x0187
# vendor   0x04f9
# sernum   000H5J658204

attach 100 {
   match "product"      "0x0187";
   match "vendor"       "0x04f9";
   match "sernum"       "000H5J658204";
   action   "/bin/ln -sf /dev/$device-name /dev/brPRN";
};

# For detach USB printer, For 6.x, 7.x
detach 100 {                                              # 定义设备拔出时的动作
   device-name "ulpt[0-9]+";
                                                          # 当设备拔除时,删除相应的连接
   action   "/bin/rm /dev/`/bin/ls -l /dev | /usr/bin/awk ‘/^l.*$device-name\$/{print \$9}’`";
};

在上面的示例文件生效后,当EPSON Stylus CX3700联机时,devd服务进程就会根据配置文件指定的条件,创建一个指向自动分配给这个打印机的节点的名为/dev/epPRN的连接。对于Brother FAX-2820,则创建/dev/brPRN的连接。

FreeBSD 8.x 以后,devd实现了在设备拔除时也能给出product、vendor、sernum等信息,这样拔除设备时删除连接的方式就不需要写一大串天书一样的代码(这样的代码用来炫耀还是不错的;P)

# For 8.x or later
detach 100 {
   match "product"      "0x0187";
   match "vendor"       "0x04f9";
   match "sernum"       "000H5J658204";
   action   "/bin/rm -f /dev/brPRN";
};

这样,无论两台是单独联机还是同时联机,也不管两台打印机联机的先后次序,/dev/epPRN总是指向为EPSON Stylus CX3700创建的设备节点,而/dev/brPRN总是指向为Brother FAX-2820创建的设备节点。

保存配置文件后,重新启动devd服务,配置就可以生效了。

#/etc/rc.d/devd start

如果没有生效,再次前台运行调试模式的devd来查看有关信息排除错误。

应用程序配置

经过这样的设置,在CUPS配置时就不用为设备节点名称不固定而头疼了,配置EPSON Stylus CX3700时,打印机URI使用usb:/dev/epPRN,而Brother FAX-2820则使用usb:/dev/brPRN。其他热插拔设备应当可以参照上述方法设置。

原文链接:http://wiki.freebsdchina.org/doc/s/devfs

FreeBSD系统检测AMD处理器的硬件温度

FreeBSD系统检测AMD处理器的硬件温度

摘要:

这个wiki页面主要介绍如何在FreeBSD系统中如何检测AMD处理器的温度;
所写内容主要适用于k8以及k10系列处理器。

基本原理:

在处理器内部有一个温度传感器;
为了读取这个温度需要将适当的驱动程序编译或者加载进入内核。

具体操作:

在系统内核配置文件中增加k8temp的驱动,也既是添加下述内容到内核的配置文件中去:

device k8temp
然后重新编译安装内核即可。

如果不想重新编译内核,也可以采用加载模块的方法,把下述内容添加进入loader.conf即可:

k8temp_load=”YES”

检测温度:

在加载合适的驱动之后,系统就可以读取处理器内部传感器的温度了,系统将这个温度数值保存在sysctl的相应节点中,所以可以通过输入sysctl的相关信息来显示处理的温度。

检测方法如下:

sysctl -a | grep -i temp

注意:

根据k8temp(4)中的内容,k8temp这个驱动是在FreeBSD 7.1才进入系统的内核的,所以只有在7.1版本之后才可以直接通过内核加载。

对于之前的版本,似乎可以通过ports系统安装。

本文内容适用于7.2版本,由于在8.0版本中驱动的名字有所调整,所以8.0用户应将的将驱动调整为“device amdtemp”,

比较简单的方法是看看/boot/kernel/下面模块的名字,在FreeBSD系统中所有模块的名字都和自己的功能存在对应关系,

例如运行下述命令可以找出哪些模块和温度相关。

ls /boot/kernel | grep -i temp

如果在8.0系统上运行上述命令时,还可以发现Intel的Core对应的驱动是“device coretemp”。

参考:

k8temp(4)<URL:http://www.freebsd.org/cgi/man.cgi?query=k8temp&apropos=0&sektion=0&manpath=FreeBSD+7.2-RELEASE&format=html>

amdtemp(4)<URL:http://www.freebsd.org/cgi/man.cgi?query=amdtemp&sektion=4&apropos=0&manpath=FreeBSD+8.0-RELEASE>

loader.conf(5)<URL:http://www.freebsd.org/cgi/man.cgi?query=loader.conf&sektion=5&apropos=0&manpath=FreeBSD+7.2-RELEASE>

sysctl(8)

原文链接:http://wiki.freebsdchina.org/doc/a/amd_cpu_temperature

TCP最大连接数限制

TCP最大连接数限制

一直以来,有很多技术人员都有”TCP的最大连接数有65535的限制”的这种误解。今天在这边向大家解释一下。

在FreeBSD中有一个设置kern.ipc.maxsockets可以对系统中最大的描述符做限制。只要这个值可以超过65535,那么最大连接数为65535的限制就不攻自破了。
那么这个值到底是int32还是int16呢?

FreeBSD 7.2 p4 /usr/src/sys/kern/uipc_socket.c中写的很明白

uipc_socket.c:164
int    maxsockets;

uipc_socket.c:243
static void
init_maxsockets(void *ignored)
{
TUNABLE_INT_FETCH(“kern.ipc.maxsockets”, &maxsockets);
maxsockets = imax(maxsockets, imax(maxfiles, nmbclusters));
}

maxsockets很明显是int32,一个32位的整形数字。

原文链接:http://ray.bsdart.org/archives/221.raymond

gcc预定义宏

gcc预定义宏

gcc在编写跨平台的项目时需要用到以下的定义宏:

#if defined (__FreeBSD__) || defined (linux) \
|| defined (__hpux) || defined (sun) || defined (_AIX) \
|| defined (__OS2__) || defined (__EMX__)

要查看gcc定义的所有预定义宏,使用命令:cpp -dM /dev/null

#define __DBL_MIN_EXP__ (-1021)
#define __FLT_MIN__ 1.17549435e-38F
#define __DEC64_DEN__ 0.000000000000001E-383DD
#define __CHAR_BIT__ 8
#define __WCHAR_MAX__ 2147483647
#define __DBL_DENORM_MIN__ 4.9406564584124654e-324
#define __FLT_EVAL_METHOD__ 0
#define __DBL_MIN_10_EXP__ (-307)
#define __FINITE_MATH_ONLY__ 0
#define __DEC64_MAX_EXP__ 384
#define __SHRT_MAX__ 32767
#define __LDBL_MAX__ 1.18973149535723176502e+4932L
#define __UINTMAX_TYPE__ long unsigned int
#define __DEC32_EPSILON__ 1E-6DF
#define __unix 1
#define __SCHAR_MAX__ 127
#define __USER_LABEL_PREFIX__
#define __STDC_HOSTED__ 1
#define __DEC64_MIN_EXP__ (-383)
#define __DBL_DIG__ 15
#define __FLT_EPSILON__ 1.19209290e-7F
#define __LDBL_MIN__ 3.36210314311209350626e-4932L
#define __DEC32_MAX__ 9.999999E96DF
#define __unix__ 1
#define __DECIMAL_DIG__ 21
#define __LDBL_HAS_QUIET_NAN__ 1
#define __GNUC__ 4
#define __MMX__ 1
#define __FLT_HAS_DENORM__ 1
#define __FreeBSD_cc_version 700003
#define __DBL_MAX__ 1.7976931348623157e+308
#define __DBL_HAS_INFINITY__ 1
#define __DEC32_MIN_EXP__ (-95)
#define __LDBL_HAS_DENORM__ 1
#define __DEC32_MIN__ 1E-95DF
#define __DBL_MAX_EXP__ 1024
#define __DEC128_EPSILON__ 1E-33DL
#define __SSE2_MATH__ 1
#define __amd64 1
#define __LONG_LONG_MAX__ 9223372036854775807LL
#define __GXX_ABI_VERSION 1002
#define __FLT_MIN_EXP__ (-125)
#define __x86_64 1
#define __DBL_MIN__ 2.2250738585072014e-308
#define __LP64__ 1
#define __DBL_HAS_QUIET_NAN__ 1
#define __DEC128_MIN__ 1E-6143DL
#define __REGISTER_PREFIX__
#define __DBL_HAS_DENORM__ 1
#define __NO_INLINE__ 1
#define __DEC_EVAL_METHOD__ 2
#define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL
#define __FLT_MANT_DIG__ 24
#define __VERSION__ “4.2.1 20070719 [FreeBSD]”
#define __DEC64_EPSILON__ 1E-15DD
#define __DEC128_MIN_EXP__ (-6143)
#define unix 1
#define __SIZE_TYPE__ long unsigned int
#define __DEC32_DEN__ 0.000001E-95DF
#define __ELF__ 1
#define __FLT_RADIX__ 2
#define __LDBL_EPSILON__ 1.08420217248550443401e-19L
#define __FreeBSD__ 7
#define __SSE_MATH__ 1
#define __k8 1
#define __LDBL_DIG__ 18
#define __KPRINTF_ATTRIBUTE__ 1
#define __x86_64__ 1
#define __FLT_HAS_QUIET_NAN__ 1
#define __FLT_MAX_10_EXP__ 38
#define __LONG_MAX__ 9223372036854775807L
#define __FLT_HAS_INFINITY__ 1
#define __DEC64_MAX__ 9.999999999999999E384DD
#define __DEC64_MANT_DIG__ 16
#define __DEC32_MAX_EXP__ 96
#define __DEC128_DEN__ 0.000000000000000000000000000000001E-6143DL
#define __LDBL_MANT_DIG__ 64
#define _LONGLONG 1
#define __DEC32_MANT_DIG__ 7
#define __k8__ 1
#define __WCHAR_TYPE__ int
#define __FLT_DIG__ 6
#define __INT_MAX__ 2147483647
#define __FLT_MAX_EXP__ 128
#define __DBL_MANT_DIG__ 53
#define __DEC64_MIN__ 1E-383DD
#define __WINT_TYPE__ unsigned int
#define __SSE__ 1
#define __LDBL_MIN_EXP__ (-16381)
#define __amd64__ 1
#define __LDBL_MAX_EXP__ 16384
#define __LDBL_MAX_10_EXP__ 4932
#define __DBL_EPSILON__ 2.2204460492503131e-16
#define _LP64 1
#define __GNUC_PATCHLEVEL__ 1
#define __LDBL_HAS_INFINITY__ 1
#define __INTMAX_MAX__ 9223372036854775807L
#define __FLT_DENORM_MIN__ 1.40129846e-45F
#define __FLT_MAX__ 3.40282347e+38F
#define __SSE2__ 1
#define __FLT_MIN_10_EXP__ (-37)
#define __INTMAX_TYPE__ long int
#define __DEC128_MAX_EXP__ 6144
#define __GNUC_MINOR__ 2
#define __DBL_MAX_10_EXP__ 308
#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L
#define __STDC__ 1
#define __PTRDIFF_TYPE__ long int
#define __DEC128_MANT_DIG__ 34
#define __LDBL_MIN_10_EXP__ (-4931)
#define __GNUC_GNU_INLINE__ 1

原文链接:http://ray.bsdart.org/archives/172.raymond

基于libfdk库的FreeBSD系统优化

基于libfdk库的FreeBSD系统优化

1> kern.ipc.maxsockets

设定系统最大可以开启的 socket 数目。与libfdk中session管理的最大客户端数目。

然而,这个值必须在系统一开机就设定好,所以如果要修改这项设定,我们必须修改 /boot/loader.conf 才行。例如,我们要将它改成最多同时可以有 16424 个 socket,则必须在 /boot/loader.conf 中加入下列这一行:

kern.ipc.maxsockets=”16424”

2> net.inet.ip.portrange.*

libfdk中的UDP服务器框架有可能使用到工作端口范围4000-8000,所以我们必须手动调整一下 net.inet.ip.portrange.last 这个值,将它调为 10000、20000、甚至 40000 都是合理的。如果要在一开机就调整这个值,我们可以修改 /etc/sysctl.conf,并增加下列这一行:

net.inet.ip.portrange.last=40000

3> kern.ipc.shm_use_phys

kern.ipc.shm_use_phys 这个选项预设为 0 (关闭),我们可以将它设为 1 (打开)。如果我们将它设成 1,这个功能允许内核通过将共享内存页锁定在核心存储中而消除大量的内部内存管理和页面跟踪的开销,使得它们不可被换出,如果我们有大量的程序 (数百个) 需要共同分享一个小的共享内存空间,或者是共享内存空间很大时,我们可以将这个值打开。

这个值可以在开机完成后才设定,因此只要放在 /etc/sysctl.conf 中即可:

kern.ipc.shm_use_phys=1

4> vfs.vmiodirenable

这个选项预设被设为 1,也就是打开的状态。它被用来决定一个目录中的结构 (目录下的其它文件名称等等) 被快取在内存中的行为。一般的目录结构可能都不大,而这些目录结构会被快取在物理内存中。物理内存中所存放的目录结构快取有限,所以不管我们的物理内存有多大,预设都只会快取一定大小的目录结构。如果我们将这个选项打开,系统将 buffer cache 放在虚拟内存的快取中,目录结构也就会被存放在虚拟内存中。这样的好处是所有的内存空间都可以被拿来做目录的快取,而缺点是最小用来存放目录结构的快取会从 512 bytes 变成 4K。

如果您的系统物理内存空间有限,建议您将这个选项关闭。但如果您的系统需要进行大量档案操作,例如 proxy、多人使用的邮件服务器、或是 news server 等,建议将这个选项打开。

5> vfs.write_behind

这个选项预设为 1,也就是打开的状态。在打开时,在系统需要写入数据在硬盘或其它储存设备上时,它会等到收集了一个 cluster 单位的数据后再一次写入,否则会在一个暂存区空间有写入需求时就立即写到硬盘上。这个选项打开时,对于一个大档案写入速度非常有帮助。但如果您遇到有很多行程延滞在等待写入动作时,您可能必须关闭这个功能。

6> vfs.hirunningspace

这个值决定了系统可以将多少数据放在写入储存设备的等候区。通常使用默认值即可,但当我们有多颗硬盘时,我们可以将它调大为 4MB 或 5MB。但必须注意的是,太大的值反而会造成效能低落。

7> net.inet.tcp.sendspace 及 net.inet.tcp.recvspace

这二个选项分别控制了网络 TCP 联机所使用的传送及接收暂存区的大小。预设的传送暂存区为 32K,而接收暂存区为 64K。如果需要加速 TCP 的传输,可以将这二个值调大一点,但缺点是太大的值会造成系统核心占用太多的内存。如果我们的机器会同时服务数百或数千个网络联机,那么这二个选项最好维持默认值,否则会造成系统核心内存不足。但如果我们使用的是 gigabite 的网络,将这二个值调大会有明显效能的提升。传送及接收的暂存区大小可以分开调整,例如,假设我们的系统主要做为网页服务器,我们可以将接收的暂存区调小一点,并将传送的暂存区调大,如此一来,我们就可以避免占去太多的核心内存空间。

还有要注意的是,除了这二个选项可以控制网络传输暂存区大小外,route 这个指令也可以用来依路由路径的不同指定暂存区大小。另外 ipfw 等防火墙软件也可以用来限制每个联机所能使用的网络频宽。

如果我们将传送或接收的暂存区设为大于 65535,除非我们的服务器本身及客户端所使用的操作系统支持 TCP 协议的 windows scaling extension (请参考 RFC 1323 文件)。FreeBSD 预设已支援 rfs1323 (即 sysctl 的 net.inet.tcp.rfc1323 选项)。

8> net.inet.tcp.always_keepalive

当这个选项打开时,系统会定期送出「keepalives」以检查一个 TCP 联机是否中断。在打开的状况下,所有运作的网络程序都会有定时检查联机是否中断的功能,否则只有当应用程序本身支持时才有此功能。这个选项打开的好处是让系统更便于管理网络联机,尤其是当我们系统中常有一些莫名其妙就中断联机的使用者时。例如,当一个使用者利用拨接连到系统时,很可能在完成一个完整的 TCP 联机之前,就因为拨接中断而造成联机异常中断。当然,在某些情况下,也有可能会造成系统误判网络联机已中断而结束这个 TCP 联机。

9> net.inet.tcp.delayed_ack

TCP 协议有一个特性,就是当收到客户端的数据时,会传回一个 ACK (acknowledgement) 的封包,以确认已收到数据。然而,我们也可以将 ACK 封包和所要回传的资料一起送出。例如,当我使用 telnet 进入系统时,在输入指定时,当我们在键盘上敲打一个字符,系统会送回一个表示已接收到该字符的 ACK 封包,并传回一个含有该字符的封包以在终端机上显示。当 net.inet.tcp.delayed_ack 打开时,系统会将 ACK 和显示该字符的封包一传送,而不需分成二个封包。所以这个选项打开时,可以将封包数量减少一半,以加速网络传输。其它的网络服务,例如,WWW、 SMTP、POP3 等也都具有这种特性。
在高速网络和低负载的情况下会略微提高性能,但在网络连接较差的时候,对方计算机得不到应答会持续发起连接请求,反而会降低性能。

10> kern.ipc.somaxconn

这个选项控制了 TCP 联机等候区最多可以等待的联机数量,其默认值为 128,不过这个值对于一台忙碌的服务器而言可能小了点。例如大型的网页服务器、邮件服务器,我们可以将它设为 1024。要注意的是在一些网络服务的程序中,如 Apache 及 sendmail 也有自己的等待数量设定,我们可能也要在那些软件上做一些设定才会让 kern.ipc.somaxconn 发生作用。将这个选项的值调大一点还有一个好处,就是在面对 Denial of service 的攻击时,有较好的防卫能力。

11> kern.maxfiles

这个选项控制了系统中支持最多开启的档案数量,这个值通常是几千个档,但对于一台忙碌的数据库系统或是会开启许多档案的服务器而言,我们可以将它调高为一、二万。

12> kern.maxusers

这是用来控制系统内部表格(internal system tables)大小的参数,它的值大约是您期望系统同一时间会上线使用的使用者数量。我们在核心设定档中有一个 maxusers 的选项,如果您使用的是 FreeBSD 4.5 以上的版本,建议您只要在核心设定档中将它 0 即可,系统会在一开机时自动依您的内存大小调整这个值。如果我们使用的是 FreeBSD

4.5 以后的版本,要调整这个值时,我们可以在 /boot/loader.conf 中加入该选项的设定,例如:

kern.maxusers=256

如果您使用 FreeBSD 4.4 以前的版本,则只能重新编译核心以改变这项设定。

这个值一定要设定大于四,maxusers 的值决定了处理程序所容许的最大值,20+16*maxusers 就是你将得到的所容许处理程序。系统一开机就必须要有 18 个处理程序 (process),即便是简单的执行指令 man 又会产生 9 个 process,所以将这个值设为 64 应该是一个合理的数目。如果你的系统会出现 proc table full 的讯息的话,可以就把它设大一点,例如 128。除非您的系统会需要同时开启很多档案,否则请不要设定超过 256。

13> kern.ipc.nmbclusters

这个值用来调整系统在开机后所要分配给网络 mbufs 的 cluster 数量,由于每个 cluster 大小为 2K,所以当这个值为 1024 时,也是会用到 2MB 的核心内存空间。我们可以简单的估计出大约需要的大小,例如,假设我们的网页同时约有 1000 个联机,而 TCP 传送及接收的暂存区大小都是 16K,则最糟的情况下,我们会需要 (16K+16K) * 1024,也就是 32MB 的空间,然而所需的 mbufs 大概是这个空间的二倍,也就是 64MB,所以所需的 cluster 数量为 64MB/2K,也就是 32768。对于内存有限的机器,建议值是 1024 到 4096 之间,而当拥有海量存储器空间时,我们可以将它设定为 4096 到 32768 之间。我们可以使用 netstat 这个指令并加上参数 -m 来查看目前所使用的 mbufs 数量。

当我们要修改这个值是,必须在一开机就修改,所以只能在 /boot/loader.conf 中加入修改的设定,例如:

kern.ipc.nmbclusters=16384

14> net.inet.ip.fastforwarding

如果打开的话每个目标地址一次转发成功以后它的数据都将被记录进路由表和arp数据表,节约路由的计算时间,但会需要大量的内核内存空间来保存路由表。

原文链接:http://ray.bsdart.org/archives/142.raymond