终于有了间茅草棚

——我走时,会否有随风飘散的痕迹?

外面的风好大,雨也淅淅沥沥的。

世间种种的诱惑不惊不扰我清梦,山高路远不绝我追踪你绝美的笑容,登高一呼时才懂始终在为你心痛,俯首对花影摇动都是东风在捉弄

世间种种的迷惑都是因你而猜错,水光月光又交融描述这朗朗的夜空,生死到头的相从似狂花落叶般从容,当一切泯灭如梦就在远山被绝
随笔 - 42, 文章 - 2, 评论 - 269, 引用 - 3

导航

<2010年3月>
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910

留言簿(10)

随笔档案

文章档案

收藏夹

其它的我

友情连接

网页连接

搜索

最新评论

  • 1. re: 陈刚
  • 中间件主要的好处在于便于整合,就像一个接口规范和标准。像游戏开发中3D图形技术有两套,有的游戏直接基于D3D或OenGL开发,现在更多的是基于一些图形引擎,像Ogre,Irrlicht等,在这些图形引擎下面去和具体的图形API打交道,从这个意义上来说Ogre和Irrlicht拥有一定的中间件的涵义(这些图形引擎不只是中间层,还包含有场景管理、渲染逻辑等更多内容)。加了这样一层后,当支持新的D3D10和D3D11时,中间层作出修改,原应用不需要修改就可运行,还有移植到支持OpenGLES的设备时,也是可行的。
  • --清风雨
  • 2. re: linux常见开发问题,.JPEG parameter struct mismatch
  • 你说的3.JPEG parameter struct mismatch没看明白,我现在也遇到了同样的问题,
    ”编译libjpeg的make文件里定位输出生成jpeg的地方“指的是哪啊,
    “打印出相关参数”也不明白
    “前台运行同样的./configure”什么意思?
    帮帮我了,谢谢!我邮箱litao_hao@16.com   qq;40362095
  • --haolitao
  • 3. re: linux移植建议
  • 这个学习了
  • --陈刚
  • 4. re: 软件开发模式猜测
  • 脚本在其可配置性、可扩展性上性能应该是已经超越了中间件技术。

    中间件在对其扩展、更新、配置时不知是否能做到依赖它的程序不中断运行呢
  • --陈刚
  • 5. re: 软件开发模式猜测
  • 对 “中间件模式” 还真不太了解。 

    不知 “中间件模式” 是否会影响运行、调试以及维护成本,以及如何能抽象出中间层?
  • --陈刚
  • 6. re: void *几用
  • class Sample
    {
    public:
        void draw( void *g );
    };

    我个人其实并不太认同这种做法,虽然实现了抽象但会加大维护代价
  • --陈刚
  • 7. re: 用自己的话浅谈封装
  • 封装也是一个不断完善的过程,当然再经过一段时间后随着技术的进步思想的成熟,也会推翻重来。
  • --陈刚
  • 8. re: linux常见开发问题
  • xargs不错,蛮有用的。
  • --hATEmATH的网上田园
  • 9. re: 关于“元编程”的浅思考
  • --免费打工仔
  • 10. re: 关于质数(素数)的算法

  • 是AKS方法。
    http://mathworld.wolfram.com/AKSPrimalityTest.html


  • --perry
  • 11. re: 关于质数(素数)的算法
  • 为了在数字比较小时计算得快些,可以应用一些初等数论的结论:

    1]
    仅计算6n+1和6n+5(n=1,2,3,...)形式的数。易知6n+2和6n+4是2的倍数,6n+3是3的倍数。因为2和3的倍数最多。
    2]
    根据“合数的最大的素因数都不大于它的平方根”定理,每次分解仅算到被分解的平方根为止即可。
    证明(一般的证明都不完整):
    设N=P*Q,P和Q是N的不少于1个素因数的乘积(指出这点很重要)。反证法可证P和Q都小于或等于N的平方根(否则P*Q>N)。等号当且仅当P=Q=N的平方根时成立(这时N是一个素数的平方)。

    1]可减少2/3的计算量,2]可再减少1/2的计算量。即为原计算量的1/6。

    几百位数位的数,建议采用ASK方法。





  • --perry
  • 12. re: 关于质数(素数)的算法

  • 素因数分解是一个NP问题。
  • --perry
  • 13. re: 关于质数(素数)的算法
  • 1121=19*59
  • --李圆欢
  • 14. re: void *几用
  • 方法都不错
  • --员工生日礼物
  • 15. re: void *几用
  • to oshj:
    最近才悟道这个用法,没想到你都用了很多了。

    to brent:
    不是为了玩才玩,这里每种用法在特定的情况下,都有他相应的好处。不过,我是做为自己记录的,指不定什么时候就忘记了,还可以这么用。
    1. 可以使得头文件简单,而且出于实现保密的需要,还是很有用处的。
    2. 很多时候对象本身应该简洁,但往往应对不同的需要,通常需要数据对应。举个例子,比如玩家在哪个房间,在哪个房间最好不要直接记在玩家身上,用数据注入的方式,能够很快的获得该信息。
    3. 因为是做为库暴露头文件的,使用者并不关心void *的实际意义,而且能够加快编译速度。真正要关心时,就Graphics.h这个头文件是不够的,通常会需要了解整底层个实现,才能较好的扩充。
  • --清风雨

阅读排行榜

评论排行榜

几种函数形式的速度比较

    最近在考虑函数速度的优化问题。一般函数分为普通函数和inline函数,因为既然inline是编译器展开,那么我何不手动展开试试呢。在频繁访问数据的情况下,他们各自的速度对比是怎样的?
    通常情况,inline比普通调用要快,但是,如果我是通过对象A调用访问对象B的数据呢?普通函数相对inline真的慢?inline手动展开了,要好几次访问B,然后再访问数据;而普通的调用,只需要访问一次B的调用;手动展开了,会不会比编译器展开的快呢,而且或许还可以做些手动优化。
    以下用了一个很简单的例子,做了一个简要的测试。
#include<cstdio>;

#include <windows.h>

#pragma comment( lib,"winmm" )

#define C 10*1000*1000

namespace speed
{
    class testImpl
    {
    public:
        testImpl( void ) : data( 0 ) {}
        void clear( void ) { data = 0; }
        void test1( void )
        {
            for( unsigned long long i = 0ULL; i < C; ++i )
            {
                ++data;
            }
        }
        inline void test2( void )
        {
            for( unsigned long long i = 0ULL; i < C; ++i )
            {
                ++data;
            }
        }
        int data;
    };
    class testClass
    {
    public:
        testImpl *m_Impl;
    public:
        testClass( void )
        {
            m_Impl = new testImpl();
        }
        ~testClass( void )
        {
            delete m_Impl;
        }
        void test1( void )
        {
            m_Impl->test1();
            m_Impl->clear();
        }
        void test2( void )
        {
            m_Impl->test2();
            m_Impl->clear();
        }
        void test3( void )
        {
            for( unsigned long long i = 0ULL; i < C; ++i )
            {
                ++m_Impl->data;
            }
            m_Impl->clear();
        }
    };
    static void test( void )
    {
        testClass aTest;
        ::timeBeginPeriod( 1 );
        int t0 = ::timeGetTime();
        aTest.test1();
        int t1 = ::timeGetTime();
        aTest.test2();
        int t2 = ::timeGetTime();
        aTest.test3();
        int t3 = ::timeGetTime();
        ::timeEndPeriod( 1 );
        std::printf( "time of normal/inline/expand : %d/%d/%d\r\n",t1-t0,t2-t1,t3-t2 );
        std::printf( "value = %d",aTest.m_Impl->data );
    }
};

在我的机器上(AMD Althon XP 2200+    512M)得到了以下平均值(多次输出,比较趋向中间值的结果):
debug :
time of normal/inline/expand : 84/67/85
value = 0
release:
time of normal/inline/expand : 36/16/19
value = 0

posted on 2005-12-11 19:58 终于有了间茅草棚 阅读(3998) 评论(7)  编辑 收藏

评论

# re: 几种函数形式的速度比较

复杂度过高的inline编译器不会进行inline,而会生成对应的正常函数,进行调用。没有看明白你想表达什么啊,指点下吧。
2005-12-11 21:03 | lostpencil

# re: lostpencil

哪里有什么指点啊。

开始觉得我这里给的情况,inline其实就是展开,那么,要多次通过B对象访问数据,要多次取B的地址,再取数据。而普通的,应该只需要取一次B的地址,以后的都是本对象的函数访问了,那样就在CPU的cache里了。
2005-12-11 21:39 | 清风雨

# re: 几种函数形式的速度比较

首先我假设你的test2()真的在testClass::test2()内被展开.
其伪码应该为:
void testClass::test2( void )
{
/**testImpl::test2() begin**/
{
   testImpl* const __impl=m_Impl;
   for( unsigned long long i = 0ULL; i < C; ++i )
   {
                __impl->++data;
   }
}
/**testImpl::test2() end**/
m_Impl->clear();
}

而testImpl::test1()又会是什么? 
因为C++规定non-virtual member function其调用成本等同一个普通函数调用, 因此testImpl::test1()所对应的C伪码应该是:
void __testImpl_test1(testImpl *const This){
   for( unsigned long long i = 0ULL; i < C; ++i )
   {
                This->++data;
   }
}

而testClass::test1()则变为
void __testClass_test1(testClass *const This){
      __testImpl_test( &This->m_Impl );
      ....
}

也就是不会出现"inline其实就是展开,那么,要多次通过B对象访问数据,要多次取B的地址,再取数据。"这种情况.
或者说testClass::test2()比testClass::test1()省了出入栈时间而已.
如果你是用VC编绎的话, 据我所知必需要用参数强迫编绎器才会内联展开.
还有就是类成员函数分为: inline, static, virtual, friend四大类.
而调用效率区别最大的是non-virtual和virtual,  
你所比较的两种都是non-virtual所以效率并不会有太大的差别.
2005-12-12 00:21 | hpho

# re: hpho

1. 可能你写的比较匆忙,或者说应为是伪码,不过,稍微有些问题。
2. 对virtual和非virtual 实在没什么好比的
3. friend只不过是一个申明,另外个人唯恐避之不急
4. 很容易的,我们都会容易想的将多次访问改为本地访问,正如release对test3展开的优化(对比debug很能说明问题)
void test3( void )
{
    testImpl *impl = m_Impl;    
    for( unsigned long long i = 0ULL; i < C; ++i )
    {
        ++impl->data;
    }
    impl->clear();
}
4. 为什么这样展开后test3比test2还要慢呢?也就是还是inline快呢?所以,我觉得以上数据或许能说明点什么。
5. 这样一次记录,下次,我可以免去再测试。当然,inline的情况不同,或许另当别论。
6. 毫无疑问,我们常采用的本对象函数访问的inline,显然最快,所以,我只是测试一下AB访问的情况是否会慢一点(因为我开始这么觉得,多次的频繁,开销应该比压盏出盏高,我手动的局部化可能要快,那到底情况如何呢)。
2005-12-12 09:33 | 清风雨

# re: 几种函数形式的速度比较

代码凭空写语法上应该有错, 不过只要能描述出大意就行了.

   /***testClass::test2()***/
   testImpl* const __impl=m_Impl; 
   for( unsigned long long i = 0ULL; i < C; ++i ) 
   { 
                ++__impl->data; 
   } 


  /***testClass::test3()***/

for( unsigned long long i = 0ULL; i < C; ++i )
{
               ++m_Impl->data
}

区别在于后者是++this->m_Impl->data;你的手动展开的test3可能多了一次间接寻址. 你试试把test3改为像test2的那样先赋值给一个testImpl的指针再用此指针访问data看看release版的结果会不会一样.

你说non-virtual和virtual没什么好比那两种non-virtual更没什么好比的, 不竟大家都知道inline不是必然的. 还有我们猜测编绎器行为其实是有些不切实制. :-P
2005-12-12 10:05 | hpho

# re: hpho

我说virtual和普通函数没什么好比,主要是这个同样的函数而言,virtual显然慢嘛!——多了一个虚函数指针查询过程。
但是,同样是non-virtual的,我要看看具体的差别。
你说的有道理,我前面写的展开是针对release对test3的优化,等会回去,我看看手动优化,再看看结果。
另外:这个const加的好!
2005-12-12 10:35 | 清风雨

# re: hpho

测试结果和给编译器自动优化结果基本一样。不过,很遗憾的是,当我打算看看汇编码时,debug下的test1和test2得到了一样的结果(即使我强制inline),release,编译器甚至直接跳到test1去了。那么也就是编译器对这个循环没有inline(也怪自己debug和release下看到输出差别,就没细究)。而对于手动展开,当我为了避免干扰,扩大循环次数时,结果表现是最差的。
但,不管怎么说,我们可以认为inline(如果能够,它还是最优的)是个不错的选择,而手动的优化,显然失败了。
另外,输出结果的差异,可能有较大的扰动(必要时,还需要足够的放大,甚至调用先后的调整——这个顺序,我怀疑和cache有关)。

附,以下是MSDN关于内联的说明(最后一句话很重要):
内联函数展开”(/Obn) 选项控制函数的内联展开,其中 n 是下列之一:
选项 说明 
/Ob0 禁用内联展开(默认情况下是打开的)。 
/Ob1 只展开标记为 inline 或 __inline 的函数,或在类声明内定义的 C++ 成员函数中的函数。 
/Ob2 展开标记为 inline 或 __inline 的函数和编译器选择的任何其他函数(由编译器自行进行展开,通常称作自动内联)。 
当使用 /O1、/O2 或 /Ox 时 /Ob2 有效。

此选项要求使用 /O1、/O2、/Ox 或 /Og 启用优化。

编译器将内联展开选项和关键字视为建议。不保证函数将内联展开。无法强制编译器内联特定函数。

2005-12-12 21:30 | 清风雨
标题  
姓名  
主页
验证码 *
内容   
  登录  使用高级评论  Top
[使用Ctrl+Enter键可以直接提交]