洋's profileA Better DayPhotosBlogListsMore Tools Help

Blog


    September 23

    快结婚了

    快结婚了,
    Lj说我是快有家的人了.
    是啊,一转眼成快有家的人了...眨眼

    怀念曾经的<音乐天堂>

     
        <音乐天堂>好象离开我们好久了,不过我还是依然如此地怀念,就在每一次重新翻开旧日杂志的时刻,就在和天堂群中朋友聊天的
    过程中,嘿.一种美丽就这样留在心中!
        目前还未能再找到象<音乐天堂>那样出色的杂志......
        从某种意义上来说,大学四年我从《音乐天堂》所获取的,也许要远远大于我从大学课堂所学得的知识。它在我的面前展示了一
    个广博的音乐海洋,得以让我摆脱了音乐上的浅薄无知。我相信,音乐品位的高低在某种程度上可以影响一个人的生活品味,精神状
    态和处世态度……
        所以在这一点上,我有理由对《音乐天堂》感激涕零,是它让我脱胎换骨,它是我真正意义上的大学课本……
     
    ps:怀念雷老大的忽悠(外一篇)
     
        大学期间包括高中时期,雷老大的无时无处的忽悠使我的音乐眼界有了质的提高。

        至今,想起他对各种音乐流派的指点江山;对我们随处看到抑或听到的cd、唱片的出处、来历娓娓道来,如数家珍;对各个音乐
    人、音乐大家的趣闻轶事的侃侃而谈,并时不时加上几句脱线的名言,那叫一个畅快;想起他那没人敢乱动,成堆成堆摆放的装满CD
    的大纸箱;想起他那满屋随处可见的音乐杂志,依然还是心怀敬意,现在想起来依然是不由得不高山仰止。

        到今天,无论听广播还是看电视,未见哪个主持人在音乐思想的深度或广度可与其比肩。
     
        怀念听雷老大忽悠那个年代,放荡不羁的年代……
     
     
    September 19

    计算机语言乱语

     

        C语言是有趣的,因为它是“计算机科学”发展的产物。

        PythonRuby是有趣的,因为它是“天才”的产物。

        Delphi是有趣的,因为他是史上“最优美的结构化编程教学语言Pascal”的延伸。

        与之不同的是多数的资深程序员认为VB/PHPJava是无趣的——PHP是快速WEB生产需求催化的产物。VBJava则是软件工程发展的产物。

        当“编程”遇上“快速生产”和“工程”的时候,乐趣就开始退化了。然而与乐趣无关的是,他们三个却成为了现代软件工业中最成功的三把斧头。一把能快速的砍出一个WEB论坛;一把能跨速的砍出Client界面;一把则通过理念、框架、规范、中间件等等等等,使得软件开发更加模式化和规范化,令软件行业向大规模工业化生产方式向前迈进了一大步。

        VBPHPJava本身都是成功的,而陷于三者的程序员则多半难以成功。我们现在常常赞赏地说:XX技术XX框架让程序员更关注于业务逻辑。我们在享受他们所带来的便捷的同时,也正在慢慢丧失程序员的天性——创造力。

     

     

    女人 男人 金钱

     
     男人没钱时恨女人俗气
     有钱时恨不得女人都俗气

    家庭 金钱

    一个人的声望看他的母亲,
    一个人的地位看他的父亲,
    一个人的智慧看他的孩子,
    一个人的富有看他的老婆。
    September 15

    Why OO sucks


    原文: http://www.sics.se/~joe/bluetail/vol1/v1_oo.html
    作者:Joe Armstrong

    当我第一次知道OOP的概念时,我非常疑惑,但是不知道为啥——它仅仅在感觉上“不对”。
    在OOP问世之后变得粉流行(稍后解释为什么),而批评OOP就像“在教堂里咒骂”。
    OO成为了每个受尊敬的语言必须具备的一部分。

    而当Erlang变得越来越流行时,我们经常问一个问题“Erlang是OO的吗?”
    当然正确的答案是“当然不是”——但是我们没有大肆宣扬——我们只是换了种精心设计的说法,Erlang是某种OO但不是真的是。

    这时我想起在法国巴黎时IBM的老板在7th IEEE逻辑编程大会上的演讲。
    IBM prolog添加了许多OO扩展,当人们问起时他说:“我们的客户想要OO的prolog,所以我们构建了OO的prolog”

    我想到了“多么简单,没有良心的疑虑,没有灵魂的搜索,没有‘这是正确的事情’的问题。。。”

    为什么OO很恶心

    我对OOP的反对原则源自一些基本的概念,我将概述其中一些反对意见。

    反对之一——数据类型和方法应该绑定在一起
    对象将方法和数据结构绑定在一起成为不可分割的单元。我认为这是基本的错误,因为方法和数据结构属于完全不同的世界。为啥哩?

    1,方法做事情。它们是输入和输出。输入和输出的是方法所改变的数据结构。
    在大部分编程语言里,方法由命令式语句顺序构建:“做这件事然后那件事。。。”
    理解方法首先得理解做事情的顺序(在懒惰函数编程语言和逻辑语言中这个限制被放宽了)
    2,数据结构是结构。它们不做任何事情。它们本质上是声明。“理解”数据结构比“理解”方法简单多了。

    方法作为黑盒子来转换输入和输出。如果我理解输入和输出,这样我就理解了方法。这并不意味着我可以写这个方法。

    方法通常理解为在一个计算系统里用来将数据结构T1转换为数据结构T2的东西。

    既然方法和数据结构是完全不同类型的动物,那么将它们锁在一个笼子里就是完全错误的。

    2,反对之二——任何东西都必须为对象
    考虑“时间”。在OO语言里“时间”也必须是对象。但是在非OO语言里一个“时间”是一个数据结构的实例。
    例如,在Erlang里有许多不同类型的时间,它们可以使用类型声明来明确指定:
    Java代码
    1. -deftype day() = 1..31.  
    2. -deftype month() = 1..12.  
    3. -deftype year() = int().  
    4. -deftype hour() = 1..24.  
    5. -deftype minute() = 1..60.  
    6. -deftype second() = 1..60.  
    7. -deftype abstime() = {abstime, year(), month(), day(), hour(), min(), sec()}.  
    8. -deftype hms() = {hms, hour(), min(), sec()}.  
    9. ...  
    -deftype day() = 1..31.
    -deftype month() = 1..12.
    -deftype year() = int().
    -deftype hour() = 1..24.
    -deftype minute() = 1..60.
    -deftype second() = 1..60.
    -deftype abstime() = {abstime, year(), month(), day(), hour(), min(), sec()}.
    -deftype hms() = {hms, hour(), min(), sec()}.
    ...
    

    注意这些定义不属于任何特殊的对象。它们很普遍,并且数据结构表示的时间可以被系统中的任何方法处理。

    没有相关联的方法。

    反对之三——在一个OOP语言里数据类型定义散布到任意位置
    在OOP语言里数据类型定义属于对象。
    这样我就不能在一个地方找到所有的数据类型定义。
    在Erlang或者C里我可以在一个单独的include文件或数据字典里定义我所有的数据类型。
    在一个OOP语言里我不能——数据类型定义散布到任意位置。

    让我举一个例子。假设我想定义一个通用的数据结构。通用数据类型是一个数据类型,它在系统中的任意位置出现。

    lisp程序员知道,拥有一个较小数量的通用数据类型和在它上面的大量的小方法会更好。

    通用数据类型就比如linked list,或者一个array或者一个hash table或者更高级的对象如time或者date或者filename。

    在一个OOP语言里我不得不选择一些base对象来在里面定义通用的数据结构,所有其他想使用这些数据结构的对象必须继承该对象。
    假设现在我想创建一些“time”对象,那么它应该属于哪个对象呢。。。

    反对之四——对象拥有私有状态
    状态是所有罪恶的根源。特别是有副作用的方法应该避免。

    在编程语言里状态是令人讨厌的,而真实世界里状态却千奇百怪的存在着。
    我对我的银行账户的状态很感兴趣,当我从我的账户存钱或取钱时我希望我的银行账户状态成功更新。

    既然状态在真实世界里存在,那么编程语言应该提供什么能力来处理状态呢?

    1,OOP语言说“将状态隐藏”。状态仅仅通过访问方法来隐藏和可见。
    2,传统编程语言(C,Pascal)说状态的可见度由语言的scope规则来决定。
    3,纯声明式语言说没有状态。系统的全局状态转移到方法里然后从方法里出来。
    类似于monad(函数式编程语言)和DCG(逻辑语言)等机制被用来隐藏状态,这样它们可以像“有没有状态无所谓”一样来编程,但是对系统状态的完全访问是必需的。

    OOP语言所选择的“隐藏状态”可能是最坏的选择。
    它们不是将状态显示出来并寻找减少状态的坏处的方式,而是将状态隐藏起来。

    为什么OO粉流行?

    1,原因1——它被认为很容易学
    2,原因2——它被认为让代码更易重用
    3,原因3——它被大肆宣传
    4,原因4——它创建了一个新的软件工业

    我看不到原因1和原因2的证据。原因看起来像是技术背后的驱动力。
    如果一个编程语言技术如此之差,然后它创建了一个新的工业来解决它自己本身的问题,则它会成为想从中牟利的人的好工具。

    这就是OOP背后真正的驱动力。
    September 10

    c的高内聚,低耦合

    一般来说,同一个c文件里面实现的函数,在可执行文件里面,代码应该可是相邻的。如果一个c文件里面的函数,只有相互之间的调用,而没有调用其他文件里面的函数,那么在执行这些代码时,cache的命中率会很高,这样可可以视为高内聚。减少不同文件里面函数的交叉引用,应该对整体性能有帮助。或者可以借助 link script来把相关联的函数编译到一个section里面。不过这种做法,最后的结果不能预测,性能有时高,有时低,所以还是在一开始就规划好接口,把相关文件放到一个c文件里面好。
    任何程序都会有热点,把热的地方放到一起,可以避免频繁的cache切换。
    从cpu cache角度来优化程序,如果没有cache hit或者cache miss的测量工具,就非常困难。目前还没有发现什么好用的工具。

    转载一篇不错的文章,来自Linux内核文档

    Chinese translated version of Documentation/oops-tracing.txt

    If you have any comment or update to the content, please contact the
    original document maintainer directly. However, if you have a problem
    communicating in English you can also ask the Chinese maintainer for
    help. Contact the Chinese maintainer if this translation is outdated
    or if there is a problem with the translation.

    Chinese maintainer: Dave Young
    ---------------------------------------------------------------------
    Documentation/oops-tracing.txt 的中文翻译

    如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文
    交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻
    译存在问题,请联系中文版维护者。

    中文版维护者: 杨瑞 Dave Young
    中文版翻译者: 杨瑞 Dave Young
    中文版校译者: 李阳 Li Yang
    王聪 Wang Cong

    以下为正文
    ---------------------------------------------------------------------

    注意: ksymoops 在2.6中是没有用的。 请以原有格式使用Oops(来自dmesg,等等)。
    忽略任何这样那样关于“解码Oops”或者“通过ksymoops运行”的文档。 如果你贴出运行过
    ksymoops的来自2.6的Oops,人们只会让你重贴一次。

    快速总结
    -------------

    发现Oops并发送给看似相关的内核领域的维护者。别太担心对不上号。如果你不确定就发给
    和你所做的事情相关的代码的负责人。 如果可重现试着描述怎样重构。 那甚至比oops更有
    价值。

    如果你对于发送给谁一无所知, 发给linux-kernel@vger.kernel.org。感谢你帮助Linux
    尽可能地稳定。

    Oops在哪里?
    ----------------------

    通常Oops文本由klogd从内核缓冲区里读取并传给syslogd,由syslogd写到syslog文件中,
    典型地是/var/log/messages(依赖于/etc/syslog.conf)。有时klogd崩溃了,这种情况下你
    能够运行dmesg > file来从内核缓冲区中读取数据并保存下来。 否则你可以
    cat /proc/kmsg > file, 然而你必须介入中止传输, kmsg是一个“永不结束的文件”。如
    果机器崩溃坏到你不能输入命令或者磁盘不可用那么你有三种选择:-

    (1) 手抄屏幕上的文本待机器重启后再输入计算机。 麻烦但如果没有针对崩溃的准备,
    这是仅有的选择。 另外,你可以用数码相机把屏幕拍下来-不太好,但比没有强。 如果信
    息滚动到了终端的上面,你会发现以高分辩率启动(比如,vga=791)会让你读到更多的文
    本。(注意:这需要vesafb,所以对‘早期’的oops没有帮助)

    (2)用串口终端启动(请参看Documentation/serial-console.txt),运行一个null
    modem到另一台机器并用你喜欢的通讯工具获取输出。Minicom工作地很好。

    (3)使用Kdump(请参看Documentation/kdump/kdump.txt),
    使用在Documentation/kdump/gdbmacros.txt中定义的dmesg gdb宏,从旧的内存中提取内核
    环形缓冲区。

    完整信息
    ----------------

    注意:以下来自于Linus的邮件适用于2.4内核。 我因为历史原因保留了它,并且因为其中
    一些信息仍然适用。 特别注意的是,请忽略任何ksymoops的引用。

    From: Linus Torvalds

    怎样跟踪Oops.. [原发到linux-kernel的一封邮件]

    主要的窍门是有五年和这些烦人的oops消息打交道的经验;-)

    实际上,你有办法使它更简单。我有两个不同的方法:

    gdb /usr/src/linux/vmlinux
    gdb> disassemble

    那是发现问题的简单办法,至少如果bug报告做的好的情况下(象这个一样-运行ksymoops
    得到oops发生的函数及函数内的偏移)。

    哦,如果报告发生的内核以相同的编译器和相似的配置编译它会有帮助的。

    另一件要做的事是反汇编bug报告的“Code”部分:ksymoops也会用正确的工具来做这件事,
    但如果没有那些工具你可以写一个傻程序:

    char str[] = "\xXX\xXX\xXX...";
    main(){}

    并用gcc -g编译它然后执行“disassemble str”(XX部分是由Oops报告的值-你可以仅剪切
    粘贴并用“\x”替换空格-我就是这么做的,因为我懒得写程序自动做这一切)。

    另外,你可以用scripts/decodecode这个shell脚本。它的使用方法是:
    decodecode 43 04 39 42 54
    7e 04 40 89 42 54 8b 43 04 3b 05 00 f6 52 c0

    最后,如果你想知道代码来自哪里,你可以:

    cd /usr/src/linux
    make fs/buffer.s # 或任何产生BUG的文件

    然后你会比gdb反汇编更清楚的知道发生了什么。

    现在,问题是把你所拥有的所有数据结合起来:C源码(关于它应该怎样的一般知识),
    汇编代码及其反汇编得到的代码(另外还有从“oops”消息得到的寄存器状态-对了解毁坏的
    指针有用,而且当你有了汇编代码你也能拿其它的寄存器和任何它们对应的C表达式做匹配
    )。

    实际上,你仅需看看哪里不匹配(这个例子是“Code”反汇编和编译器生成的代码不匹配)。
    然后你须要找出为什么不匹配。通常很简单-你看到代码使用了空指针然后你看代码想知道
    空指针是怎么出现的,还有检查它是否合法..

    现在,如果明白这是一项耗时的工作而且需要一丁点儿的专心,没错。这就是我为什么大多
    只是忽略那些没有符号表信息的崩溃报告的原因:简单的说太难查找了(我有一些
    程序用于在内核代码段中搜索特定的模式,而且有时我也已经能找出那些崩溃的地方,但是
    仅仅是找出正确的序列也确实需要相当扎实的内核知识)

    _有时_会发生这种情况,我仅看到崩溃中的反汇编代码序列, 然后我马上就明白问题出在
    哪里。这时我才意识到自己干这个工作已经太长时间了;-)

    Linus

    ---------------------------------------------------------------------------
    关于Oops跟踪的注解:

    为了帮助Linus和其它内核开发者,klogd纳入了大量的支持来处理保护错误。为了拥有对
    地址解析的完整支持至少应该使用1.3-pl3的sysklogd包。

    当保护错误发生时,klogd守护进程自动把内核日志信息中的重要地址翻译成它们相应的符
    号。

    klogd执行两种类型的地址解析。首先是静态翻译其次是动态翻译。静态翻译和ksymoops
    一样使用System.map文件。为了做静态翻译klogd守护进程必须在初始化时能找到system
    map文件。关于klogd怎样搜索map文件请参看klogd手册页。

    动态地址翻译在使用内核可装载模块时很重要。 因为内核模块的内存是从内核动态内存池
    里分配的,所以不管是模块开始位置还是模块中函数和符号的位置都不是固定的。

    内核支持允许程序决定装载哪些模块和它们在内存中位置的系统调用。使用这些系统调用
    klogd守护进程生成一张符号表用于调试发生在可装载模块中的保护错误。

    至少klogd会提供产生保护错误的模块名。还可有额外的符号信息供可装载模块开发者选择
    以从模块中输出符号信息。

    因为内核模块环境可能是动态的,所以必须有一种机制当模块环境发生改变时来通知klogd
    守护进程。 有一些可用的命令行选项允许klogd向当前执行中的守护进程发送信号,告知符
    号信息应该被刷新了。 更多信息请参看klogd手册页。

    sysklogd发布时包含一个补丁修改了modules-2.0.0包,无论何时一个模块装载或者卸载都
    会自动向klogd发送信号。打上这个补丁提供了必要的对调试发生于内核可装载模块的保护
    错误的无缝支持。

    以下是被klogd处理过的发生在可装载模块中的一个保护错误例子:
    ---------------------------------------------------------------------------
    Aug 29 09:51:01 blizard kernel: Unable to handle kernel paging request at virtual address f15e97cc
    Aug 29 09:51:01 blizard kernel: current->tss.cr3 = 0062d000, %cr3 = 0062d000
    Aug 29 09:51:01 blizard kernel: *pde = 00000000
    Aug 29 09:51:01 blizard kernel: Oops: 0002
    Aug 29 09:51:01 blizard kernel: CPU: 0
    Aug 29 09:51:01 blizard kernel: EIP: 0010:[oops:_oops+16/3868]
    Aug 29 09:51:01 blizard kernel: EFLAGS: 00010212
    Aug 29 09:51:01 blizard kernel: eax: 315e97cc ebx: 003a6f80 ecx: 001be77b edx: 00237c0c
    Aug 29 09:51:01 blizard kernel: esi: 00000000 edi: bffffdb3 ebp: 00589f90 esp: 00589f8c
    Aug 29 09:51:01 blizard kernel: ds: 0018 es: 0018 fs: 002b gs: 002b ss: 0018
    Aug 29 09:51:01 blizard kernel: Process oops_test (pid: 3374, process nr: 21, stackpage=00589000)
    Aug 29 09:51:01 blizard kernel: Stack: 315e97cc 00589f98 0100b0b4 bffffed4 0012e38e 00240c64 003a6f80 00000001
    Aug 29 09:51:01 blizard kernel: 00000000 00237810 bfffff00 0010a7fa 00000003 00000001 00000000 bfffff00
    Aug 29 09:51:01 blizard kernel: bffffdb3 bffffed4 ffffffda 0000002b 0007002b 0000002b 0000002b 00000036
    Aug 29 09:51:01 blizard kernel: Call Trace: [oops:_oops_ioctl+48/80] [_sys_ioctl+254/272] [_system_call+82/128]
    Aug 29 09:51:01 blizard kernel: Code: c7 00 05 00 00 00 eb 08 90 90 90 90 90 90 90 90 89 ec 5d c3
    ---------------------------------------------------------------------------

    Dr. G.W. Wettstein Oncology Research Div. Computing Facility
    Roger Maris Cancer Center INTERNET: greg@wind.rmcc.com
    820 4th St. N.
    Fargo, ND 58122
    Phone: 701-234-7556

    ---------------------------------------------------------------------------
    受污染的内核

    一些oops报告在程序记数器之后包含字符串'Tainted: '。这表明内核已经被一些东西给污
    染了。 该字符串之后紧跟着一系列的位置敏感的字符,每个代表一个特定的污染值。

    1:'G'如果所有装载的模块都有GPL或相容的许可证,'P'如果装载了任何的专有模块。
    没有模块MODULE_LICENSE或者带有insmod认为是与GPL不相容的的MODULE_LICENSE的模块被
    认定是专有的。

    2:'F'如果有任何通过“insmod -f”被强制装载的模块,' '如果所有模块都被正常装载。

    3:'S'如果oops发生在SMP内核中,运行于没有证明安全运行多处理器的硬件。 当前这种
    情况仅限于几种不支持SMP的速龙处理器。

    4:'R'如果模块通过“insmod -f”被强制装载,' '如果所有模块都被正常装载。

    5:'M'如果任何处理器报告了机器检查异常,' '如果没有发生机器检查异常。

    6:'B'如果页释放函数发现了一个错误的页引用或者一些非预期的页标志。

    7:'U'如果用户或者用户应用程序特别请求设置污染标志,否则' '。

    8:'D'如果内核刚刚死掉,比如有OOPS或者BUG。

    使用'Tainted: '字符串的主要原因是要告诉内核调试者,这是否是一个干净的内核亦或发
    生了任何的不正常的事。污染是永久的:即使出错的模块已经被卸载了,污染值仍然存在,
    以表明内核不再值得信任。

    September 09

    我们不是天使

    我们不是天使,哪怕再虔诚的双手,也无法改变生活的轨迹。
                                                       来自远远Blog