??xml version="1.0" encoding="utf-8" standalone="yes"?>久久这里只精品国产99热,国产精品美女久久久久AV福利 ,MM131亚洲国产美女久久http://m.shnenglu.com/pwq1989/archive/2016/01/19/212688.html叛_叛_Tue, 19 Jan 2016 08:13:00 GMThttp://m.shnenglu.com/pwq1989/archive/2016/01/19/212688.htmlhttp://m.shnenglu.com/pwq1989/comments/212688.htmlhttp://m.shnenglu.com/pwq1989/archive/2016/01/19/212688.html#Feedback1http://m.shnenglu.com/pwq1989/comments/commentRss/212688.htmlhttp://m.shnenglu.com/pwq1989/services/trackbacks/212688.html0x0

前些天组里老司机@梁希在jvm的项目榨q机器性能之余Qؓ了检查下gcc~译器和Intel Xoen CPU的正性,写了一l测试代码测试了下mfence指o的效?/p>

`
mfence Opcode : 0F AE /6

Performs a serializing operation on all load-from-memory and store-to-memory instructions that were issued prior the MFENCE instruction. This serializing operation guarantees that every load and store instruction that precedes in program order the MFENCE instruction is globally visible before any load or store instruction that follows the MFENCE instruction is globally visible. The MFENCE instruction is ordered with respect to all load and store instructions, other MFENCE instructions, any SFENCE and LFENCE instructions, and any serializing instructions (such as the CPUID instruction).
Weakly ordered memory types can be used to achieve higher processor performance through such techniques as out-of-order issue, speculative reads, write-combining, and write-collapsing.
The degree to which a consumer of data recognizes or knows that the data is weakly ordered varies among applications and may be unknown to the producer of this data. The MFENCE instruction provides a performance-efficient way of ensuring load and store ordering between routines that produce weakly-ordered results and routines that consume that data.
It should be noted that processors are free to speculatively fetch and cache data from system memory regions that are assigned a memory-type that permits speculative reads (that is, the WB, WC, and WT memory types). The PREFETCHh instruction is considered a hint to this speculative behavior. Because this speculative fetching can occur at any time and is not tied to instruction execution, the MFENCE instruction is not ordered with respect to PREFETCHh instructions or any other speculative fetching mechanism (that is, data could be speculatively loaded into the cache just before, during, or after the execution of an MFENCE instruction).
`

单来说就是一个可以在CPU乱序执行中保证真实的load/store序的指?br />

0x1
老司机写了一个小E序(注:有误?
// file: order.c

#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

union p64 {
    int i;
    char padding[64];
    long align8;
};

volatile union p64 v1, v2;
int b;

void *
run1(void *ignore)
{
    for (;;) {
        while (!b);
        if (v1.i || v2.i) {
            puts("assert error 1");
            exit(-1);
        }
        v1.i = 1;
        asm ("sfence": : :"memory");
        v2.i = 1;
        asm ("sfence": : :"memory");
        b = 0; 
    }
}

int
main()
{
    pthread_t p;
    pthread_create(&p, NULL, run1, NULL);
    int cnt = 0;

    for (;; cnt++) {
        v1.i = v2.i = 0;
        asm ("sfence": : :"memory");
        b = 1;
        asm ("sfence": : :"memory");
        int icnt = 0;
        for (;; icnt++) {
            int i1 = v1.i;
            asm ("lfence": : :"memory");
            int i2 = v2.i;
            if (i1 && i2)   break;
            if (i1 < i2) {
                printf("assert error, cnt = %d, icnt = %d, i1 = %d, i2 = %d\n", cnt, icnt, i1, i2);
                exit(-1);
            }
        }
    }
    return 0;
}

大概逻辑是: 一共有3个变量,v1.iv2.ib ,起了2个线E,一个顺序写入v1和v2Q一个读v1和v2Q互盔R过改变b的值来通讯Q然后两个线E不停@环?/p>

q个E序会挂?br />printf("assert error, cnt = %d, icnt = %d, i1 = %d, i2 = %d\n", cnt, icnt, i1, i2); 
q条断言上,意思是U程1在顺序写入v1和v2Q但是主U程却出现读?v1=0Qv2=1的情c?br />

0x2

然后我帮忙去看了一下,觉得q种写法甚是_暴Q于是原L搬了一个c++11?

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <atomic>
#include <thread>

using namespace std;

union p64 {
    atomic<int> i;
    char padding[64];
    long align8;
};

volatile union p64 v1, v2;
atomic<int> b;

void *
run1()
{
    int rcnt = 0;
    for (;; rcnt++) {
        while (!b.load());
        if (v1.i.load() || v2.i.load()) {
            puts("assert error 1");
            exit(-1);
        }
        v1.i.store(1);
        v2.i.store(1);
        b.store(0);
    }
}

int
main()
{
    // init
    v1.i.store(0);
    v2.i.store(0);
    thread t(run1);
    int cnt = 0;
    for (;; cnt++) {
        v1.i.store(0);
        v2.i.store(0);
        b.store(1);
        int icnt = 0;
        for (;; icnt++) {
            int b2 = b.load();
            int i1 = v1.i.load();       // *****
            int i2 = v2.i.load();       // *****
            if (i1 && i2)   break;
            if (i1 < i2) {
                printf("assert error, cnt = %d, icnt = %d, i1 = %d, i2 = %d\n", cnt, icnt, i1, i2);
                exit(-1);
            }
            if (i1 == 0 && i2 == 0 && b2 == 0) break;
        }
    }
    return 0;
}

因ؓ是原L搬,所以肯定还是会挂,但是毕竟语义上更好理解了

我们先来分析一下ؓ什么会?/p>

  • U程1对于v1Qv2的写入顺序一定是一致的
  • Memory Barrier也保证了他们写入序对其他线E的可见性(很有qh性的一点)
  • 但是ȝE却可以d v1=0,v2=1的情?/li>
  • 所以情况就是虽焉序写入了Q但是别的线E没有看到正的序Q?/li>
  • Intel: q不是!
  • 原因是搞错了因果关系Q他真正保证的顺序是当你dv2的new value的时候,那么v1也一定被写入了?/li>
  • 解决Ҏ是互换上面代码中我?*星号**标注出的两行
  • done

在旧写法中,挂掉的情冉|U程1写入v1 = 1Q主U程读v1Q没有读刎ͼ那么ȝE认为v1?Q然后线E?l箋写入v2Q主U程d了,ȝE认为v2??然后挂在了断a上?/p>

两行互换后,ȝE首先读取v2Q如果v2已经?了,那么v1也一定是1Q反之亦然?/p>

0x3

当然Q想让跑通那个例子不需要那么多的atomic<>Q精之后利用c++11的memory_order可以写成如下Q?br />

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <atomic>
#include <thread>

using namespace std;

union p64 {
    int i;
    char padding[64];
    long align8;
};

volatile union p64 v1, v2;
atomic<int> b;    // variable b as a guard

void *
run1()
{
    int rcnt = 0;
    for (;; rcnt++) {
        while (!b.load());
        if (v1.i || v2.i) {
            puts("assert error 1");
            exit(-1);
        }
        v1.i = 1;
        v2.i = 1;
        b.store(0, memory_order_release);
    }
}
int
main()
{
    // init
    v1.i = 0;
    v2.i = 0;
    thread t(run1);
    int cnt = 0;

    for (;; cnt++) {
        v1.i = 0;
        v2.i = 0;
        b.store(1, memory_order_release);
        int icnt = 0;
        for (;; icnt++) {
            int b2 = b.load(memory_order_acquire);
            if (b2 != 0) {
                continue
            }
            int i1 = v1.i;
            int i2 = v2.i;
            if (i1 && i2)   break;
            if (i1 < i2) {
                printf("assert error 2, cnt = %d, icnt =  %d, i1 = %d, i2 = %d\n", cnt, icnt, i1, i2);
                exit(-1);
            }
        }
    }
    return 0;
}

利用变量b在两个线E之间同步,如下?br />

 (Thead 1)

   v1.i = 1;
   v2.i = 1;
   
   b.store(0, memory_order_release) <---+
                                                             |
                                                synchronize with b
                                                 (happend before)
                                                             |
                                                            +----->  b.load(memory_order_acquire)
                                                                          
                                                                        i1 = v1.i
                                                                        i2 = v2.i

                                                                       (Thread 2)

我们查看下生成的代码
g++ -std=c++11 -pthread -g -O2 order.cpp

 v1.i = 1;
  400be6:       c7 05 d0 10 20 00 01    movl   $0x1,0x2010d0(%rip)        # 601cc0 <v1>
  400bed:       00 00 00 
        v2.i = 1;
  400bf0:       c7 05 86 10 20 00 01    movl   $0x1,0x201086(%rip)        # 601c80 <v2>
  400bf7:       00 00 00 
        memory_order __b = __m & __memory_order_mask;
        __glibcxx_assert(__b != memory_order_acquire);
        __glibcxx_assert(__b != memory_order_acq_rel);
        __glibcxx_assert(__b != memory_order_consume);

        __atomic_store_n(&_M_i, __i, __m);
  400bfa:       c7 05 5c 10 20 00 00    movl   $0x0,0x20105c(%rip)        # 601c60 <b>
  400c01:       00 00 00 
        b.store(0, memory_order_release);

  

  400a58:       8b 05 02 12 20 00       mov    0x201202(%rip),%eax        # 601c60 <b>
            int b2 = b.load(memory_order_consume);
            if (b2 != 0) {
  400a5e:       85 c0                   test   %eax,%eax
  400a60:       75 f3                   jne    400a55 <main+0x55>
                continue
            }
            int i1 = v1.i;
  400a62:       8b 0d 58 12 20 00       mov    0x201258(%rip),%ecx        # 601cc0 <v1>
            int i2 = v2.i;
  400a68:       44 8b 05 11 12 20 00    mov    0x201211(%rip),%r8d        # 601c80 <v2>

看来Intel的Strong Memory Model已经保证了这一点,Memory Barrier都不需要了

Q虽然标题里面有MemoryBarrierQ但是内定w面根本没涉及的样子。。)



叛_ 2016-01-19 16:13 发表评论
]]>
systemtap + tengine lua 性能试W记http://m.shnenglu.com/pwq1989/archive/2015/01/09/209448.html叛_叛_Fri, 09 Jan 2015 04:03:00 GMThttp://m.shnenglu.com/pwq1989/archive/2015/01/09/209448.htmlhttp://m.shnenglu.com/pwq1989/comments/209448.htmlhttp://m.shnenglu.com/pwq1989/archive/2015/01/09/209448.html#Feedback0http://m.shnenglu.com/pwq1989/comments/commentRss/209448.htmlhttp://m.shnenglu.com/pwq1989/services/trackbacks/209448.html序言

虽然nginx+lua开发一些小的web服务单快P但是׃U种原因Q配套的工具比较~ZQ监控工具和性能工L{。而且lua作ؓ一U跑在虚拟机的脚本语aQ虽然做的短精悍,但是。。。功能和可调优的I间q是Ơ缺了点?/p>

前段旉使用春哥?a style="box-sizing: border-box; color: #428bca; text-decoration: none; background: transparent;">systemtap脚本Ҏ的lua服务做了下性能试Q这里记录一下折腄历程

准备

systemtap是一个性能和调试跟踪的工P最开始是Z调试内核被做出来的,后来d了用h跟t的功能?/p>

折腾记录

春哥的脚本要求systemtap2.2以上Q公司测试服务器自带的systemtap脚本的版本那?.6Q远q不够,所以必L动编译一个。下载systamtap的源码,然后./configuare + make可以直接编了。最开始碰到的问题是公司el5pȝ的服务器的elfutil版本太低Q得自己~译一个高版本的elfutil然后指定路径。。。。我怕麻烦,把一个空的测试机器重装成el6Qelfutil的版本立马就够了(我真是太机智??/p>

利~译出systamtap之后(中途遇Csystemtap版本不够新导致的W号找不到的bug)Q就是tengine的安装,旉都折腑֜q上面了。。。我们项目用的是tengine-adsq个版本Q直接用tengine~少模块Q就请了tenginel的同学帮忙把模块给打了q去。由于要跟踪lua内部Q所以自带的luajit必须-g~译。那边的同学比较忙,我就只能自己要了服务器权限跑上去自己~,~了几次之后那个试服务器竟然磁盘满了。。。M是折腾了一晚上和一早上Q终于把带debuginfo的tenginel装上了?/p>

效果

启动tengine服务Q把压测E序开好,q行

./ngx-sample-lua-bt -p 29237 --luajit20 -t 200 -a '--vp 02 -R /home/wenqian.peiwq/systemtap-2.6/runtime -DSTP_NO_OVERLOAD --all-modules -DMAXSKIPPED=1024 ' > tmp.bt 

采样l束后,利用brendangregg?a style="box-sizing: border-box; color: #428bca; text-decoration: none; background: transparent;">FlameGraph tools可以l制栈调用的火焰图,如下Q?/p>

flamegraph

通过q个图,先是立马发现了一个低U错误。。。(上面贴的图上已经没了Q,我有很多打印debug的语句,用了q类用法

_log.log("debug", "xxx", util.print_r(some_data)) 

忘记了lua的求值策略,虽然debug下的q个语句在生产环境中不执行,但是׃求值策略,util.print_r(some_data)仍然会先求|D了很大的性能损失Q接q?/4?/p>

同时也发CUUID的生成所占用的时间也q分的长了一些,然后重写了这个方法,使用了resty.string库中的random模块(直接调用了ngx_*的C函数)Q然后利用systemtapҎ了前后的旉Q提升了360%多,可见q是很有效果的?/p>

?

q个目是基于我上次手撸的小框架dodoluQ根据这ơ的试l果Q框架的装Ҏ的项目造成的性能损失?%以下?/p>

叛_ 2015-01-09 12:03 发表评论
]]>
自撸web框?dodolu(Znginx lua) + lua debuggerhttp://m.shnenglu.com/pwq1989/archive/2014/12/22/209273.html叛_叛_Mon, 22 Dec 2014 10:22:00 GMThttp://m.shnenglu.com/pwq1989/archive/2014/12/22/209273.htmlhttp://m.shnenglu.com/pwq1989/comments/209273.htmlhttp://m.shnenglu.com/pwq1989/archive/2014/12/22/209273.html#Feedback1http://m.shnenglu.com/pwq1989/comments/commentRss/209273.htmlhttp://m.shnenglu.com/pwq1989/services/trackbacks/209273.html背景

前段旉目需要一个点L务,大致是要Ҏ用户h的url及数据库中的规则Q匹配出一个结果ƈ记录日志。最开始是一个很的需求,l果业务来复杂,业务逻辑中经常要处理header头和一些其他的信息Q导致代码越来越混ؕ。在一期结束之后,抽时间把q段旉的工作抽象出了一个轻量框架Q只做了适量的封装,加入了代码生成的模块Q可以帮助开发者迅速做Z个可用的web服务?/p>

介绍

dodolu框架地址(Github)?/p>

该框架只做了最化的封装,几乎没有性能损失Qƈ提供了根据配|文?meta.lua)Q自动生成route模块Qnginx.conf配置Qlogger模块的功能,减轻了开发工作量Q避免重复手写大量易错的配置或字W串变量Q有助于多h开发统一风格?/p>

详情Github的README

功能

包括三个部分Q一个是web框架Q一个是代码自动生成模块Q一个是改出的luaq程调试?/a>?/p>

web框架部分

只有1k行以下的代码Q集成了resty.template、resty.cookie、UUID生成{第三方模块。提供request、response、context、util{库方便开发h员用?/p>

代码自动生成部分

可自动生?

  1. 路由配置
  2. 日志记录模块
  3. nginx.conf

主要目的在于解决nginx配置与lua代码的分问?在日志记录中ؓ严重)?/p>

开发h员新建应用步骤:在App文g夹下Q新建lua文gQ然后填?code>do_get()Ҏ卛_处理相应的gethQ所有配|在meta/meta.lua里面?/p>

一个记录日志ƈq回1x1gif的例子:

-- q个文g下面存放你的业务逻辑
-- q个文g下面存放你的业务逻辑
local app = {} function app.do_get(ctx)      local response = ctx.response     local request = ctx.request     local cookie = ctx.cookie
    response:set_content_type("text/html")     local url = request.uri     -- do some process
    ------------- write log ---------------     -- my_log 日志模块是根据meta.lua自动生成?     local logger = ctx.get_logger('my_log')       local log_data = { a = "xxx"}     logger.write(log_data, other_params)
    ------------- return empty gif -------     response:empty_gif()     response:close() end
function app.do_post(ctx) end function app.do_put(ctx) end function app.do_delete(ctx) end
return app

luaq程调试?/h3>

文档详细?a >q里Q这里只演示下用法:
sh debug.shQ然后运行用L序,成功?br />

Lua Remote Debugger
Run the program you wish to debug
Paused at file a.lua
Type 'help' for commands

下一? n

n
Paused at file a.lua line 8
8: print("Start")


查看源码  l

> l  
source file: a.lua
2:   
3:   local tab = {
4:       foo = 1,
5:       bar = 2
6:   }
7:   
8:>> print("Start")
9:   
10:  local bb = require "b"
11:  bb.foo()
12:   
13:  for i = 1, 10 do
14:      print("Loop")


讄断点   b <file>:<line>   查看    listb

> b a.lua:11
> listb 
a.lua: 11

查看局部变? local

> local {         ["tab"] = {                 {                         ["bar"] = 2,                         ["foo"] = 1,                 },                 "table: 0x2589ee0",         }, }

查看变量   p tab

> p tab
{
        ["bar"] = 2,
        ["foo"] = 1,
}
l箋执行Q直到断? r
> r Paused at file a.lua line 11




叛_ 2014-12-22 18:22 发表评论
]]>函数式编E语a与副作用http://m.shnenglu.com/pwq1989/archive/2014/07/10/207540.html叛_叛_Thu, 10 Jul 2014 07:16:00 GMThttp://m.shnenglu.com/pwq1989/archive/2014/07/10/207540.htmlhttp://m.shnenglu.com/pwq1989/comments/207540.htmlhttp://m.shnenglu.com/pwq1989/archive/2014/07/10/207540.html#Feedback1http://m.shnenglu.com/pwq1989/comments/commentRss/207540.htmlhttp://m.shnenglu.com/pwq1989/services/trackbacks/207540.html

?/h3>

函数式编E语a有很多种定义Q宽泛的认ؓ支持高阶函数Qhigher-order functionQ就函数式语言的话Q大多数C语言都是支持函数式编E的Q例如C/C++QjavaQC#QluaQpythonQJavaScriptQScala{等。收紧一下定义的话,加入函数式语a要求的模式匹配、无副作用等要求Q那么剩下的是U函数式语言Q比较常见的有HaskellQClean{?/p>

副作用是什么和Z么有些语a惛_设计上避免副作用q个问题Qgoogle能搜出好多博文,q里׃多说了。避免副作用可以带来一些实际的好处Q比如帮你大量改写代码什么的Q误Q,而且qgcc都有 _ _ attribute _ _((pure/const))的函数扩展嘛~。比如像erlangq种依赖于副作用~程的语aQ虽然有着变量不可变这个特性,但是仍然可以dprocess携带的全局变量Q而且又没有一个好的类型系l,所以在~译的时候也不会怎么大改你的代码Q大多还是直译成字节码?/p>

注:q篇文章不是**软文**Q不会用个g(f(x))当例子l大家说无副作用多么多么好,可缓存结果拉(just a lie)~原生支持q行?just another lie)Q这些都是扯淡而且不实际的。(有机会再写个博客专门谈谈q个Q?/p>

正文

首先Q纯函数式的语言没有副作用,它不会改变Q何实际的东西Q当然也没有Q全局的)状态,q样的程序如果不配上代表副作用的输入输出当然是什么都q不了的。那么如何把副作用嵌入到本不该有副作用的语言设计中那Q当然不能直接赋|不然。。不然。。就变成命o式语a了,而且函数式语a~译中引以ؓ豪的各种优化pass几乎都不能用了。那么把有副作用的函数标注出来?当然是一个办法。还有就是把副作用的表达式都包含在context中,随着函数传递,保证序而且要保证引用的唯一性?/p>

作ؓU函数式语言的代表,Haskell和Clean对于副作用的设计实现上差别很大,下面q单说一下它们的实现Q刨根究底,其实它们做的q是同一件事情?/p>

haskell

Haskell中有一个很重要的概念:MonadQ取名自范畴论,可以_浅的认为它是定义了一pd的行为准则(>>= , returnQ。Haskell中大多数语法p都是ؓ了这个发明来的。Haskell的标准库中有很多关于副作用的cd装Q比如IORefQMVarQIOMonad{等Q他们的内部实现都会归结到ST MonadQState Thread MonadQ上Q正是这个与forall关键字的l合Q从而在语法上保证了副作用嵌入在Q纯QHaskell中的正确性?br style="box-sizing: border-box;" />ST Monad里面主要的定义是Q?/p>

 newtype ST s a = ST (STRep s a)
 type STRep s a = State# s -> (# State# s, a #)
 data STRef s a = STRef (MutVar# s a)

 runST :: (forall s. ST s a) -> a
 runSTRep :: (forall s. STRep s a) -> a

其中最关键的是ST s a ?STref s a q两个数据结构?/p>

先看看这个用法,let a0 = runST $ newSTRef 0Q会引发一个type error。因为runST的类型是(forall s.ST s a) -> a Q参?code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 14.5454540252686px; padding: 2px 4px; color: #c7254e; white-space: nowrap; border-radius: 2px; background-color: #f9f2f4;">(newSTRef 0)的类型是forall s. ST s (STRef s Int)Q最后求值后的结果是a0::STRef s IntQ显然sq了原本的定义域(也就是那层forall之外Qforall是Haskell中提?*RankNType**的关键字Q。从而用户就只能使用下面的方式:

sumST :: Num a => [a] -> a
sumST xs = runST $ do          
    n <- newSTRef 0             
    forM_ xs $ \x -> do        
    modifySTRef n (+x)     
    readSTRef n     

不用标出标出具体实现Q大家就能看Z做的事情是做了一层wrapperQ在type checker上保证被box之后不会被用户取出来乱改。至于如何做到destructive in-place updateQ这属于编译器的黑法了,语言q层只需保证语义好。(**注:**ghc的实CQST Monad标准库用Cghc的unsafe打头的内|函敎ͼ

Clean

Clean语言用的{略是线性类型系l(linear type systemQ,是Substructural type sysytem的一U。在Curry-Howard同构中对应Substructrual logic。这cȝ型系l中Q不但可以决定一个变量是什么类型,q可以约束被使用的次C序。在Mozilla出的Rust语言中,也可以看到线性类型的影子?/p>

先D个栗子~

transform :: (Int -> Int) *{#Int} -> *{#Int} 
transform f s | size s == 0 = s | otherwise = if (s.[0] == 0) {f i \\ i <-: s} {f i \\ _ <-: s & i <- [s.[0]..]}

Q不要在意奇怪的语法Q{}里面其实就是list comprehensionQ?/p>

其中*是uniqueness type的标注,q个函数的类型用haskell写出来就?code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 14.5454540252686px; padding: 2px 4px; color: #c7254e; white-space: nowrap; border-radius: 2px; background-color: #f9f2f4;">transform :: (Int -> Int) -> *[Int] -> *[Int]。这个函数虽然没有很好的看出uniqueness type的特性和传播性,但是作ؓ单的例子Q差不多是q么回事?br style="box-sizing: border-box;" />对于uniqueness type最直观的理解就是带有这个标识的cd是不能参与到以后Graph Reduction中,而且会检会不会有多?#8220;变量”指向他。上面这个函C׃会存在多个[Int]及相关的副本{着被回Ӟ而是会直接在QReadWorld中的Q内存上更新数据?/p>

最?/h3>

其实已经看出Q在上面Haskell与Clean的做法中Q一个是利用forall关键字与ST Monad+~译器黑法Q另一个是build-in在类型系l中Q但是本质都是做了一件事情,是保证RealWorld中的对象不会存在多个引用Q而且在Graph Reduction中不会被~译器搞乱顺序,q样p融入到整个纯函数式的大体pM了?/p>
本h博客地址Qhttp://m.shnenglu.com/pwq1989/Q?br />

叛_ 2014-07-10 15:16 发表评论
]]>cdpȝ与图灵完?/title><link>http://m.shnenglu.com/pwq1989/archive/2014/07/10/207536.html</link><dc:creator>叛_</dc:creator><author>叛_</author><pubDate>Thu, 10 Jul 2014 07:14:00 GMT</pubDate><guid>http://m.shnenglu.com/pwq1989/archive/2014/07/10/207536.html</guid><wfw:comment>http://m.shnenglu.com/pwq1989/comments/207536.html</wfw:comment><comments>http://m.shnenglu.com/pwq1989/archive/2014/07/10/207536.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://m.shnenglu.com/pwq1989/comments/commentRss/207536.html</wfw:commentRss><trackback:ping>http://m.shnenglu.com/pwq1989/services/trackbacks/207536.html</trackback:ping><description><![CDATA[     摘要: 序类型系l在~程语言中是极ؓ重要Q不单单是提供一个类型的标注或是方便~译Q更多时候是减少出错的可能。当cdpȝ强大C定程度,可以进行所谓的“富类型编E?#8221;Q比如在Haskell中只要编译器不报错,大致上程序也是没什么bug的。在常用的静态类型语a中,C++/java/C#{,虽然在新标准与新版本中支持类型的自动推导Q但是对cdpȝ及其推导q是~少更ؓ直接的支持。很多常用语...  <a href='http://m.shnenglu.com/pwq1989/archive/2014/07/10/207536.html'>阅读全文</a><img src ="http://m.shnenglu.com/pwq1989/aggbug/207536.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.shnenglu.com/pwq1989/" target="_blank">叛_</a> 2014-07-10 15:14 <a href="http://m.shnenglu.com/pwq1989/archive/2014/07/10/207536.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Haskell别扭的Y-Combinatorhttp://m.shnenglu.com/pwq1989/archive/2014/02/27/205964.html叛_叛_Wed, 26 Feb 2014 16:25:00 GMThttp://m.shnenglu.com/pwq1989/archive/2014/02/27/205964.htmlhttp://m.shnenglu.com/pwq1989/comments/205964.htmlhttp://m.shnenglu.com/pwq1989/archive/2014/02/27/205964.html#Feedback5http://m.shnenglu.com/pwq1989/comments/commentRss/205964.htmlhttp://m.shnenglu.com/pwq1989/services/trackbacks/205964.html
昨天在知乎上看到一个评论提CHaskell的YC实现Q就L了一下,然后qC一个实玎ͼ
1 newtype Mu a = Mu (Mu a -> a)
2 
3 y :: (a -> a) -> a
4 y f = (\h -> h $ Mu h) (\x -> f . (\(Mu g) -> g) x $ x)

嗯,真是别扭

反观一下其他语a的YC写法Q就贴一个lua的把
1 Y = function (f)
2    return function()
3       return (function(x) return x(x) end)
                   (function(x) return f(function(y) return x(x)(y) end) end)()
4    end
5 end
虽然看v来很长,但是Ҏ理解的多Q用λ表达式写出来是Q?a target="_blank" title="wiki">wikiQ?br />λf. (λx. f (x x)) (λx. f (x x))
目的是能做?Y f = f (Y f) q种效果Q之所以这么写Q是Z不引入名字(引入了名字是?Q?br />
对于Haskellq种用HMcdpȝ的语a来说Q最大的问题是不能递归的定义类型,同样是静态类型检查,比如C#Q就可以不费力的用Func和delegate做出来,haskell 额,得扭曲的利用newtype Mu a = Mu (Mu a -> a) 来绕q类型检查(当然Q这个在Haskell中是不可能构造出一个实际的值的Q?br />
看下他是怎么做的Q我们来把他展开一下:
原式子:y f = (\h -> h $ Mu h) (\x -> f . (\(Mu g) -> g) x $ x)
带进去:y f = (\x -> f . (\(Mu g) -> g) x $ x) $ Mu (\x -> f . (\(Mu g) -> g) x $ x)
再来一遍:y f = f . (\x -> f . (\(Mu g) -> g) x $ x) $ Mu (\x -> f . (\(Mu g) -> g) x $ x)

q样子,最后那个式子的f. 后面的那部分Q提?nbsp;(\x -> f . (\(Mu g) -> g) x $ x) q个公因?q当于?\h -> h $ Mu h) (\x -> f . (\(Mu g) -> g) x $ x)了(很像数学把,但也没多大关p)
最后,可以做出y f = f . (y f)了?br />
其实q个写法最关键的是 newtype Mu a = Mu (Mu a -> a)的作用,他是如何l过cd查,但是又不在运行期构造一个|x造也构造不出来Q?br />
来看下他的类型推DE,y的类型是y :: (a -> a) -> aQ所以里面f是 f :: a -> aQ所以f . (\(Mu g) -> g) x $ x q个式子可以推出里面的x?x :: Mu a 然后(\(Mu g) -> g) x 取出里面?aQ这样就成了
f a $ Mu aQ这时候Mu a = Mu (Mu a -> a) 递归定义的作用就发挥了,Zcd的推|l箋那个红色的a 推导?Mu a -> aQ这?f (Mu a -> a) 会返回一个Mu a -> aQ管他叫f'把,q样 f' (Mu a) p回一?a。有Ҏ前面?\h -> h $ Mu h) l箋讲上面提到的a变成 Mu a -> a。就是把Mu a 喂给?(Mu a -> a)Q最后还是返回一个a?br />(>_< 其实上面q段是我~出来的Q我~不下去了,我不知道ghc是怎么做这个事情的Q等我有生之q看完slpj-book-1987再想?

我们来应用一下,q回一个阶乘:
y (\f n -> if n <= 1 then 1 else n * f (n - 1)) 5?
不难看出Q最ly的类型被特化成了 ((Int -> Int) -> (Int -> Int)) -> (Int -> Int)


叛_ 2014-02-27 00:25 发表评论
]]>
C++ ?Memory Barrier http://m.shnenglu.com/pwq1989/archive/2014/01/08/205228.html叛_叛_Tue, 07 Jan 2014 16:54:00 GMThttp://m.shnenglu.com/pwq1989/archive/2014/01/08/205228.htmlhttp://m.shnenglu.com/pwq1989/comments/205228.htmlhttp://m.shnenglu.com/pwq1989/archive/2014/01/08/205228.html#Feedback0http://m.shnenglu.com/pwq1989/comments/commentRss/205228.htmlhttp://m.shnenglu.com/pwq1989/services/trackbacks/205228.htmlhttp://m.shnenglu.com/pwq1989/ 


今天里姐夫推荐了个C++的Actor框架 TheronQ就看了下源码,注释比代码还多,业界良心?br />
源码我还没看完,qC他的一个叫StringPool的类Q里面通过Ref来生成单例(SingletonQ,看了?br />
static void Reference();q个函数实现的时候,H然脑洞一开Qؓ啥没有Memory Barrier(wiki)?br />
先脓一下他的代码:
 1 StringPool *StringPool::smInstance = 0;
 2 Mutex StringPool::smReferenceMutex;
 3 uint32_t StringPool::smReferenceCount = 0;
 4 
 5 
 6 void StringPool::Reference()
 7 {
 8     Lock lock(smReferenceMutex);
 9 
10     // Create the singleton instance if this is the first reference.
11     if (smReferenceCount++ == 0)
12     {
13         IAllocator *const allocator(AllocatorManager::GetCache());
14         void *const memory(allocator->AllocateAligned(sizeof(StringPool), THERON_CACHELINE_ALIGNMENT));
15         smInstance = new (memory) StringPool();
16     }
17 }

我们先不讨论q一D代码,先看看下面的Q?br />
大家如果看过C++的Double Check Lock不可靠的q篇paper(地址)Q作者给出的解决Ҏ是这LQ?br />
 1     // First check
 2     TYPE* tmp = instance_;
 3     // Insert the CPU-specific memory barrier instruction
 4     // to synchronize the cache lines on multi-processor.
 5     asm ("memoryBarrier");
 6     if (tmp == 0) {
 7         // Ensure serialization (guard
 8         // constructor acquires lock_).
 9         Guard<LOCK> guard (lock_);
10         // Double check.
11         tmp = instance_;
12         if (tmp == 0) {
13                 tmp = new TYPE;
14                 // Insert the CPU-specific memory barrier instruction
15                 // to synchronize the cache lines on multi-processor.
16                 asm ("memoryBarrier");
17                 instance_ = tmp;
18         }
19     return tmp;

其实q两个Memory Barrier不用全屏障,W一个用d障rmb()好了。第二个需要一个写屏障wmb()?br />
我们都知道mbq个东西是ؓ了防止CPUU别的指令ؕ序被发明出来的,Q另一个是~译器别的Q和本篇文章没有多大关系Q有兴趣大家可以ȝI下Q,实现也是由^台相关的Ҏ指o(mfenceq样?l成的?br />
之所以要写成q样Q第二个mb()是ؓ了防止在构造函数完成之前提前对目标赋|但ctorq没完成Q就被挂P然后W二个线E访问的时候,认ؓ已经构造完毕,q而用不完整的数据引发奇怪的错误?br />
(W一个rmb()的作用我觉得是可有可无,加上可能是ؓ了效率把Q猜Q,强制hdinstance_的|防止q入W一个checkȝ争那个锁Q不加也是不会有错的Q因为POSIX规定mutex之间必须保持内存的可见性,所以是不需要担心读到脏数据) <-- q段是个人意见,Ƣ迎修正?br />
下面是我趴了半下午才想明白的问题。。。ؓ啥Theron中那D代码(W一D代码)不需要在lock中添加mb()Q后来往下翻了下Q发现StringPool的构造函数是I的。。根本就没有内存的写入,当然׃需要wmb()了?br />

可见QC++的多U程~程Q好?br />

叛_ 2014-01-08 00:54 发表评论
]]>
Q二QLuajit中的好轮子DynASMhttp://m.shnenglu.com/pwq1989/archive/2013/11/30/204508.html叛_叛_Sat, 30 Nov 2013 04:49:00 GMThttp://m.shnenglu.com/pwq1989/archive/2013/11/30/204508.htmlhttp://m.shnenglu.com/pwq1989/comments/204508.htmlhttp://m.shnenglu.com/pwq1989/archive/2013/11/30/204508.html#Feedback0http://m.shnenglu.com/pwq1989/comments/commentRss/204508.htmlhttp://m.shnenglu.com/pwq1989/services/trackbacks/204508.htmlhttp://m.shnenglu.com/pwq1989/

上一对Luajit的代码结构和~译q程做了单的描述Q这一就讲一下buildvm在第一步预处理dasc文g的过E和DynASMq个轮子?br />
官方q接Q?a >http://luajit.org/dynasm.html

是ؓ了让你更优雅的C里面撸汇~的一个工P我记得以前看q一个老外的blogҎq同样功能的jit code generator的语法,Luajit的作者显然品位还是很高的?br />
我们先来看看如果不用工具生生撸代码的话会发生什么?br />1、你往一D内存里面写0xB8,0x00,0x01....
2、你在文仉定义好多labelQ写个copy section的宏往内存里面复制Q你q不能确定里面到底是什么。(哦。。这个的术语叫Threaded。。。)

然后再对比下AsmJit或?a title="Xbyak" target="_blank">Xbyak的例子看看(他们的功能差不多Q,DynASMq提供了.marco实现Q就会发现语法真是sweeeet~

q是我写着玩的一个草泥马语jit解释器(https://github.com/pwq1989/GMHjitQ语法真是清新自然啊Q如果你想看工业U的应用Q可以看看Google的Haberman写的protobuf的upb库,里面用DynASMq行了jitQ号U快了多多(不去考证了)Q或者是agentzh写的sregex正则库,也是用它做了jit。一般来说DSL配上jit的话一定会快很多就错不了了?br />
下面l一个DynASM的DemoE序Q摘抄自q个blogQ?br />
 1 // DynASM directives.
 2 |.arch x64
 3 |.actionlist actions
 4  
 5 // This define affects "|" DynASM lines.  "Dst" must
 6 // resolve to a dasm_State** that points to a dasm_State*.
 7 #define Dst &state
 8  
 9 int main(int argc, char *argv[]) {
10   if (argc < 2) {
11     fprintf(stderr, "Usage: jit1 <integer>\n");
12     return 1;
13   }
14  
15   int num = atoi(argv[1]);
16   dasm_State *state;
17   initjit(&state, actions);
18  
19   // Generate the code.  Each line appends to a buffer in
20   // "state", but the code in this buffer is not fully linked
21   // yet because labels can be referenced before they are
22   // defined.
23   //
24   // The run-time value of C variable "num" is substituted
25   // into the immediate value of the instruction.
26   |  mov eax, num
27   |  ret
28  
29   // Link the code and write it to executable memory.
30   int (*fptr)() = jitcode(&state);
31  
32   // Call the JIT-ted function.
33   int ret = fptr();
34   assert(num == ret);
35  
36   // Free the machine code.
37   free_jitcode(fptr);
38  
39   return ret;
40 }

预处理之后那׃变成q样子:
 1 //|.arch x64
 2 //|.actionlist actions
 3 static const unsigned char actions[4] = {
 4   184,237,195,255
 5 };
 6  
 7 // []
 8  
 9 //|  mov eax, num
10 //|  ret
11 dasm_put(Dst, 0, num);
dasm_put是把num参数和actions[]一h入了DstQ?define Dst &stateQ的制定的内存中Q这时候已l是机器码的形式了?br />下面是对于acitons[]数组内容的解释:
184(B8)-- mov eax, [immediate] 指o的第一个字?br />237       -- 内置的标志DASM_IMM_D, 指明应该攑օ一?字节宽度的参敎ͼ与上一条指令完成一个MOV
195(C3)-- 对应ret指o
255       -- 内置的标志DASM_STOP

以上是最单的例子Qdasm_growpc()是内|的函数Q用来增长maxpc, q样在程序里面就可以方便写出jmp => label q样的指令了?br />
׃DynASM的文档很,q怺q有几个例子Q除了例子唯一能看的就是源码了Q所以在用的时候出现问题是很痛苦的。。当时写GMHjit发C蛋疼的pre-process period bugQ后来绕q去了?br />
源码文g有这么几?br />-- dynasm.lua
-- dynasm_proto.h
-- dynasm_*.lua
-- dynasm_*.h  // * x64  x86  ppc mips arm {target

用v来就是lua dynasm.lua a.dasm > a.h 

下面׃dynasm.lua开始分析下他的源码

入口是parseargs函数Q里面给的g_opt参数赋默认的|一个repeat 中调用parseopt解析参数Qopt_map是option对args的函数映?br />
函数wlineQwcommentQwsyncQwdumplines都是对输出的目标文g的操作?br />
真正的主函数?translateQ把input file变成 output fileQ在readfile中的doline函数是真正的处理q程Q里面判断是否是Assembler line之后Emit C codeQ调用dostmt(aline)。里面l有map_coreop[*]来处理section macro arch nop_ error_1 include  if endif elseif {关键字Q想深入研究的可以自己去看,其中在loadarch中根据arch加蝲不同的lua?br />
如果arch是x64的话Q本质还是require x86
来看dasm_x86.lua文g

_M.mergemapsq是关键的方法,讄?个Map的元ҎQ然后返回,相当于是把方法绑定在table里面传递了出去。处理后文g中关键的actionlist[]数组和Dasm_put(Dst, ...)的输出就是这个lua文g的方法?/div>里面提供了很多dumpҎQ可以供我们遇到问题时候调试处理过E?br />
action_names是以后生成的action_list中的内置标志定义Q必Mdasm_x86.h中的enum定义一致?/div>表明了代表的参数和长度等信息?br />q个文g里面所有的函数是做了一件事Q把你的 |...  q样子的代码处理成数l输出到目标文g中(我是汇编渣渣Q里面貌似支持SSE2??+Q看不懂Q等C后看到traced jit的时候再ȝ手册把)

预处理完成之后,是#include "dasm_x86.h"Q里面有最关键的dasm_Statel构体的定义Q几乎里面所有的函数都是对外的APIQ有init,setup,free{等Q除d始化与free之外Q有三个步骤是需要出现在你都代码中:
1、dasm_put(Dst,...) q个是自动生成的Q不用我们操心,Ҏactionlist[]和运行时的参数写入到Dst指定的内存(Dst->sectionQ中.
2、dasm_link() W二个参数是q回的代码长度大,q个函数把section合ƈCP处理偏移{等?br />3、dasm_encode() W二个参数是一个接受encode输出的buffer指针?br />
然后可以用一个函数指针,比如声明一?int (*f)(*int), int ret = f(param) 直接q行刚刚生成的机器码了?br />







叛_ 2013-11-30 12:49 发表评论
]]>Q一Q初识Luajithttp://m.shnenglu.com/pwq1989/archive/2013/11/28/204487.html叛_叛_Thu, 28 Nov 2013 11:23:00 GMThttp://m.shnenglu.com/pwq1989/archive/2013/11/28/204487.htmlhttp://m.shnenglu.com/pwq1989/comments/204487.htmlhttp://m.shnenglu.com/pwq1989/archive/2013/11/28/204487.html#Feedback4http://m.shnenglu.com/pwq1989/comments/commentRss/204487.htmlhttp://m.shnenglu.com/pwq1989/services/trackbacks/204487.htmlhttp://m.shnenglu.com/pwq1989/

W一对Luajit做一个大概的介绍Q我目前也正在慢慢的读通源码中Q以后发CC西就补充在这里?br />
大家可以从官|下载到源码Q?a >http://luajit.org/Q,也可以从GithubQ?a >https://github.com/LuaDist/luajitQdown下来Q顺便还可以看下commit记录?br />
大家对着luajit的wikil合源码看的话会更好些,因ؓ。。文档太特么了Q!

目录l构Q?br /> -- src
    -- host
    -- jit
    *.c
    *.h
    *.dasc
{等Q别的不是很重要

最开始我是从main函数开始看的,然后。。碰了一d灎ͼ后来研究下他的makefileQ发C是这样子的编译的Q脓一下关键的msvcbuild.bat的代码(q个更容易看懂)
 1 :X64
 2 minilua %DASM% -LN %DASMFLAGS% -o host\buildvm_arch.h vm_x86.dasc
 3 @if errorlevel 1 goto :BAD
 4 
 5 %LJCOMPILE% /I "." /I %DASMDIR% host\buildvm*.c
 6 @if errorlevel 1 goto :BAD
 7 %LJLINK% /out:buildvm.exe buildvm*.obj
 8 @if errorlevel 1 goto :BAD
 9 if exist buildvm.exe.manifest^
10   %LJMT% -manifest buildvm.exe.manifest -outputresource:buildvm.exe
11 
12 buildvm -m peobj -o lj_vm.obj
13 @if errorlevel 1 goto :BAD
14 buildvm -m bcdef -o lj_bcdef.h %ALL_LIB%
15 @if errorlevel 1 goto :BAD
16 buildvm -m ffdef -o lj_ffdef.h %ALL_LIB%
17 @if errorlevel 1 goto :BAD
18 buildvm -m libdef -o lj_libdef.h %ALL_LIB%
19 @if errorlevel 1 goto :BAD
20 buildvm -m recdef -o lj_recdef.h %ALL_LIB%
21 @if errorlevel 1 goto :BAD
22 buildvm -m vmdef -o jit\vmdef.lua %ALL_LIB%
23 @if errorlevel 1 goto :BAD
24 buildvm -m folddef -o lj_folddef.h lj_opt_fold.c
25 @if errorlevel 1 goto :BAD

先创Z一个buildvm.exe的中间工P来自动生成代码,分别生成?span style="font-size: 13.333333015441895px; background-color: #eeeeee;">lj_vm.objQ?/span>lj_bcdef.hQ?/span>lj_ffdef.h Q?/span>lj_recdef.h Q?/span>jit\vmdef.luaQ?/span>lj_folddef.hQ?lj_libdef.h

其中lv_vm.obj是依赖于host\buildvm_arch.h的,q个是用DynASM预处理vm_x86.dasc生成的,q个工具的具体分析会在下一博客提及?br />
先来看下上面自动生成的代码:
lj_bcdef.h:
 1 LJ_DATADEF const uint16_t lj_bc_ofs[] = {
 2 0,
 3 71,
 4 142,
 5 213,
 6 284,
 7 
 8 };
 9 
10 LJ_DATADEF const uint16_t lj_bc_mode[] = {
11 BCDEF(BCMODE)
12 BCMODE_FF,
13 BCMODE_FF,
14 BCMODE_FF,
15 BCMODE_FF,
16 BCMODE_FF,
17 
18 };

lj_bc_ofs[]可能是bc在vm代码D中的偏U量Q这个我q没深入q去调试一下)Qvm的一部分是用DynASM直接撸汇~撸出来的,wiki中也有提C一步jit化的opcode{等?br />
lj_bc_mode[]的用来根据压~后的bytecode构造,分离出操作数Q第一行的两个宏的定义?br />
#define BCMODE(name, ma, mb, mc, mm) \
  (BCM##ma|(BCM##mb<<3)|(BCM##mc<<7)|(MM_##mm<<11)),
#define BCMODE_FF 0

#define BCDEF(_) \
  /* Comparison ops. ORDER OPR. */ \
  _(ISLT, var, ___, var, lt) \
  _(ISGE, var, ___, var, lt) \
  _(ISLE, var, ___, var, le) \
  _(ISGT, var, ___, var, le) \
...
M是充斥着各种拼接h的宏

lj_ffdef.h:
1 FFDEF(assert)
2 FFDEF(type)
3 FFDEF(next)
4 FFDEF(pairs)
5 FFDEF(ipairs_aux)
6 
FFDEF的定义是?br />
1 /* Fast function ID. */
2 typedef enum {
3   FF_LUA_ = FF_LUA,    /* Lua function (must be 0). */
4   FF_C_ = FF_C,        /* Regular C function (must be 1). */
5 #define FFDEF(name)    FF_##name,
6 #include "lj_ffdef.h"
7   FF__MAX
8 } FastFunc;
差不多就是用FF_##name把上面的名字拼接hQ然后生成在enum里面Q这样就能当成是数字Q在数组中迅速找到入口了

vmdef.lua:
q个里面内容׃贴了Q包括bcname,irname,irfpm,irfield,ircall 的定义,在jit文g夹下面,用于调试{,比如在dump.lua中就有用?br />
local jit = require("jit")
assert(jit.version_num == 20002, "LuaJIT core/library version mismatch")
local jutil = require("jit.util")
local vmdef = require("jit.vmdef")  // ← ← ← ←

当你用luajit -jdump的时候,是调用的lua的jit库里面的lua函数

lj_recdef.h:
 1 static const uint16_t recff_idmap[] = {
 2 0,
 3 0x0100,
 4 0x0200,
 5 0x0300,
 6 0,
 7 0,
 8 0x0400,
 9 
10 };
11 
12 static const RecordFunc recff_func[] = {
13 recff_nyi,
14 recff_c,
15 recff_assert,
16 recff_type,
17 recff_ipairs_aux,
18 
19 };
其中recff_func[]是被注册的被traced jit 跟踪的函敎ͼ具体可是在lj_ffrecord.c里面看到
recff_idmap[]被用在lj_ffrecord_funcq个函数中,有一个关键的数据l构RecordFFDataQ用来记录在traceq程中被调用函数的参数和q回g敎ͼ和一些辅助数据,opcodeQliteral{等。通过recff_idmap[]保存的值来区分函数Q待仔细研究Q?br />

lj_folddef.h:
 1 static const FoldFunc fold_func[] = {
 2   fold_kfold_numarith,
 3   fold_kfold_ldexp,
 4   fold_kfold_fpmath,
 5   fold_kfold_numpow,
 6 
 7 };
 8 
 9 static const uint32_t fold_hash[916] = {
10 0xffffffff,
11 0xffffffff,
12 0x5b4c8016,
13 
14 };
用在FOLD optimization中,见lj_opt_fold.cQ主要在
1 if ((fh & 0xffffff) == k || (fh = fold_hash[h+1], (fh & 0xffffff) == k)) {
2       ref = (IRRef)tref_ref(fold_func[fh >> 24](J));
3       if (ref != NEXTFOLD)
4     break;
5     }
是根据数l偏U获取函敎ͼ直接执行?br />Q这个Optimation略复杂,以后的博文中再说Q?br />
----------------------------------------分割U?------------------------------------------

以上是buildvm生成代码Q在很多.c的文件中Q他加入了一些无意义的MARCOQ目的是Z能被buildvm识别?br />
下面说说src根目录下面的文gQ?br />
lauxlib.hQ?br />用户开发扩展和与C交互的时候的头文?br />
lib_*.h /.c:
֐思义Q就是利用LuaAPI写的内部标准库,会在Ҏ上表明是否会被trace ( LJLIB_REC(.) )?br />
ljamalg.c:
文g的合q?br />
lj_alloc.h /.c:
定制的Memory Allocator

lj_api.c:
Public Lua/C API.

lj_arch.h:
Target architecture selection

lj_jit.h:
jit~译器里面数据结构的定义

lj_asm.h/ .c  lj_asm_*.c lj_emit_*.h lj_target_*.h/.c :
IR~译成Machine CodeQ关键的数据l构ASMStateQ线性扫描的O(n2)分配法

lj_bc.h/ .cQ?br />Luajit字节码的定义和内存布局

lj_bcdump.c lj_bcread.c  lj_bcwrite.c:
围绕着字节码的操作

lj_carith.c:
C实现的一些数字运?/div>
lj_ccall.h/ .c  lj_ccallback.h / .c :
FFI C语言函数调用和回调绑?br />
lj_debug.h/.c :
调试与自省用

lj_def.h:
q个很重要,重要的类型和一些宏定义在这?br />
lj_c*.h/ .c:
和C语言先关的,比如cd转化Qchar理Q数据管?br />
lj_frame.h:
Luajit的栈帧管?br />
lj_func.h/.c:
Function handle和闭包有关的upvalue数据l构

lj_gc.h/.c:
GC相关QGC可以看下luajit的wikiQ里面涉及不增量式GC的paper和作者的看法

lj_gdbjit.h/.c :
对gdb的支?br />
lj_ir*.h/.c:
SSAQIR相关Q这个和bytecodeq是不一LQ操作和优化

lj_lex.h/.c  lj_parse.h/.c:
lexer和parser

lj_mcode.h/.c:
Machine Code理

lj_opt_*.h:
各种bytecode层面上的优化

lj_snap.h/.c:
快照支持

lj_state.h/.c:
LuaState和Stack的操?br />
lj_str*.h/.c  lj_tab.h/.c:
原生cdstring和table操作

lj_udata.h/.c:
cduser data的操?br />
lj_vm.h/.c  lj_vmevent.h/.c:
vm的API和事件注册(lj_vmevent_sendQ?br />
lj_vmmath.h/.cQ?br />对vm支持的math?br />
lua.h:
luaState{基本的Lual构

lualib.h:
和Lua一P标准库的API

luajit.h:
luajit 的public API

vm_*.dasc:
~译期被DynASM预处理的源文Ӟ下一讲DynASM时候介ldasc文g

wmain.c:
windows下面的main入口

和Trace相关的:
lj_crecord.h/.c  Q?C操作的trace record
lj_dispatch.h/.c :  指o分发Q调用ASMFuctionQ处理指令前的hook和记录trace用的hot countQ有一个重要的数据l构 GG_State
lj_ff*.h/.c: 上面讲lj_ffdef.h的时候提q,trace的时?记录Fast Function的调用记?br />lj_trace.h/.c: trace的具体过E?br />lj_traceerr.h : trace error


叛_ 2013-11-28 19:23 发表评论
]]> þù| ƷѾþþþõӰ| žžþȻ㽶ͼƬ| ŷձþùʵҶ԰ | þþƷһapp| þ91Ʒ91þû| ھƷþþþӰԺһ| 99ȳ˾ƷȾþ| ˾þþƷһ| þ˾Ʒһ| þþþþۺ| ۺպþóAV| ɫۺϾþþþþþþ| þ޾Ʒ| þúݺɫݺɫۺ| ҹӰþ| ɫɫۺϾþҹҹ| ŷƷþþþþþο| þ99һ| þþƷһ| ŷ龫Ʒþþþþþþžž| ˾þۺӰԺ| պƷþþվ| þseƷһƷ| þҹɫƷ| þw5www| ҹƷþþþþžŵӰ| þþĻձ| þþþø߳ëƬȫ| ŷһþ| һۺϾþù| þ99ۺϾƷ| Ʒþˬ| þֻоƷ4| þþƷһ| þۺϾƷһ | Ʒ׾þAAAƬ69| 996þùƷ߹ۿ| ĻۺϾþò| ƷѾþþþþþ| Ը߳þþþþþþþ|