Onega's profileOnegaBlogListsNetwork Tools Help

Blog


    August 06

    Test output binary speed of VC++ 2008, Intel C++ 10.1, and gcc version 3.2 20020927 (prerelease)

    The following code snippet is used to test output binary performance. The purpose of the code is for performance test, its accuracy is not verified.

    // fastinit.cpp : Defines the entry point for the console application.
    // g++ -I/cygdrive/d/opensource/boost/boost_1_35_0 -O3 fastinit.cpp -o f.exe
    #include <iostream>
    #include <string>
    #include <windows.h>
    #include <boost/scoped_array.hpp>
    class ProfileTimer
    {
    public:
        ProfileTimer(const std::string& name)
        {
            m_description = name;
            QueryPerformanceCounter( &m_start_time);
            m_start_tick = GetTickCount();
        }
        ~ProfileTimer()
        {
            DWORD used_tick = GetTickCount()-m_start_tick;
            LARGE_INTEGER  current_time;
            QueryPerformanceCounter( &current_time);
            LARGE_INTEGER  frequency;
            QueryPerformanceFrequency(&frequency);
            double seconds = (current_time.QuadPart-m_start_time.QuadPart)*1000.0/frequency.QuadPart;
            std::cout << m_description << " use " << seconds << " milliseconds, "
                << used_tick << " tick count."<< std::endl;
        }
        LARGE_INTEGER  m_start_time;
        DWORD m_start_tick;
        std::string m_description;

    };
    template<typename T>
    void fastinit(T* array_op, std::size_t count, const T& init_value)
    {
        if (sizeof(T)==1)
        {
            memset(array_op, *((int*)&init_value), count);
            return;
        }
        if (count<1)
            return;
        array_op[0] = init_value;
        int initialed_count = 1;
        int copy_bytes = sizeof(T);
        int max_bytes = sizeof(T)*count;
        while(copy_bytes < max_bytes)
        {
            int copy_count = min(max_bytes-copy_bytes, copy_bytes);
            memcpy(array_op+initialed_count, array_op, copy_count);
            copy_bytes+=copy_bytes;
        }
    }

    template<typename T>
    void forinit(T* array_op, std::size_t count, const T& init_value)
    {
        for(std::size_t i=0;i<count;i++)
            array_op[i] = init_value;
    }

    struct s1
    {
        int a;
        long b;
        float c;
        double d;
        short e;
        char f;
    };

    int main(int argc, char* argv[])
    {

        int times = 20000;
        if (argc>1)
            times = atoi(argv[1]);
        while (times<20000)
            times += times;
        const int element_count = 10240;
        std::cout << std::endl;

    #if defined _MSC_VER && !defined (__INTEL_COMPILER)
        std::cout << " VC++ " << _MSC_VER;
    #endif

    #ifdef __GNUC__
        std::cout << " GCC " << __GNUC__;
    #endif

    #ifdef __INTEL_COMPILER
        std::cout << " Intel C++ " << __INTEL_COMPILER
            << " VC++ compability level: " << __INTEL_MS_COMPAT_LEVEL;
    #endif

        std::cout << " element count:" <<element_count
            <<", loop " << times << " times." << std::endl;
        int data[element_count];
        {

            ProfileTimer a("initial int arrray with fast method");
            {
                for(int i=0;i<times; i++)
                    fastinit(data, element_count, 0x12345678);
            }
        }

        {
            ProfileTimer  b( "initial int arrray with for method");
            {
                for(int i=0;i<times; i++)
                    forinit(data, element_count, 0x12345678);
            }
        }
        boost::scoped_array<s1> s_array(new s1[element_count]);
        s1 s_one = {1,2,3,4,5,6};
        {

            ProfileTimer a("initial struct arrray with fast method");
            {
                for(int i=0;i<times; i++)
                    fastinit(s_array.get(), element_count, s_one);
            }
        }

        {
            ProfileTimer  b( "initial struct arrray with for method");
            {
                for(int i=0;i<times; i++)
                    forinit(s_array.get(), element_count, s_one);
            }
        }

        return 0;
    }

     

    VC++ 2008 Optimize level: /O2

    G++ Optimize level: -O3

    Result:

    GCC 3 element count:10240, loop 80000 times.
    initial int arrray with fast method use 4629.66 milliseconds, 4640 tick count.
    initial int arrray with for method use 822.303 milliseconds, 813 tick count.
    initial struct arrray with fast method use 7409.42 milliseconds, 7422 tick count.
    initial struct arrray with for method use 4208.53 milliseconds, 4203 tick count.

     

    Intel C++ 1010 VC++ compability level: 1 element count:10240, loop 80000 times.
    initial int arrray with fast method use 582.76 milliseconds, 578 tick count.
    initial int arrray with for method use 590.338 milliseconds, 594 tick count.
    initial struct arrray with fast method use 3487.38 milliseconds, 3484 tick count.
    initial struct arrray with for method use 4362.1 milliseconds, 4375 tick count.

    VC++ 1500 element count:10240, loop 80000 times.

    initial int arrray with fast method use 959.708 milliseconds, 969 tick count.
    initial int arrray with for method use 0.000596903 milliseconds, 0 tick count.
    initial struct arrray with fast method use 6287.94 milliseconds, 6281 tick count.
    initial struct arrray with for method use 8070.71 milliseconds, 8079 tick count.

    But, the following code can't tell difference between compilers:

    // compilertest.cpp : Defines the entry point for the console application.
    //  g++ compilertest.cpp -O3 -o b.exe
    #ifdef _MSC_VER
    #include "stdafx.h"
    #endif
    #include <windows.h>
    #include <iostream>
    int test1(int a, int b)
    {
        int ret = a*a + b*b + a*b;
        ret = ret+__LINE__;
        ret = ret * (ret+1) * (ret+2)*(ret+3);
        return ret;
    }
    int main(int argc, char* argv[])
    {
        DWORD start_tick = GetTickCount();
        int run_count = 1000000;
        if (argc>1)
            run_count = atoi(argv[1]);
        while (run_count < 1000000)
            run_count += run_count;
        int ret = 0;
        for (int i=0;i<run_count; i++)
        {
            ret = test1(__LINE__, ret);
        }
        DWORD used_tick = GetTickCount() - start_tick;

    #ifdef _MSC_VER
        std::cout << "VC++ " << _MSC_VER;
    #endif

    #ifdef __GNUC__
        std::cout << " GCC " << __GNUC__;
    #endif

        std::cout << " Run " << run_count << " loops return " << ret
            <<" takes " << used_tick << " ms." << std::endl;
        return 0;
    }

    June 13

    VC++ 2008 build error

    nafxcw.lib(afxmem.obj) : warning LNK4006: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMT.lib(new.obj); second definition ignored
    nafxcw.lib(afxmem.obj) : warning LNK4006: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMT.lib(delete.obj); second definition ignored
    nafxcw.lib(afxmem.obj) : warning LNK4006: "void * __cdecl operator new[](unsigned int)" (??_U@YAPAXI@Z) already defined in libcpmt.lib(newaop.obj); second definition ignored
    nafxcw.lib(afxmem.obj) : warning LNK4006: "void __cdecl operator delete[](void *)" (??_V@YAXPAX@Z) already defined in LIBCMT.lib(delete2.obj); second definition ignored
    Release\ipc_all_client.exe : warning LNK4088: image being generated due to /FORCE option; image may not run
    Embedding manifest...
    mt.exe : general error c101008a: Failed to save the updated manifest to the file ".\Release\ipc_all_client.exe.embed.manifest". The parameter is incorrect.

    The first error comes as early as VC++ 6.0, which I think should be fixed in VC++ as a special case, otherwise I have to add "nafxcw.lib libcmt.lib" to "Additional Dependencies" and "Ignore Specific Library" explicitly.

    The second error is intermittent and can be fixed by "rebuild".

    May 19

    Visual Assist X 10.4.1638.0 causes VC++ 2008 crash

    Just after upgraded to Visual Assist X 10.4.1638.0, my VC++ 2008 keeps crashing at startup. Restoring Visual Assist X 10.4.1626.0 fixed this problem.

    April 01

    build boost 1.35 via VC++ 2008

    C:\Program Files\Microsoft Visual Studio 9.0\VC>cd \
    C:\>set PYTHON_ROOT=c:\python25
    C:\>set PYTHON_VERSION=2.5
    C:\>set ICU_PATH=D:\src\ICU\icu4c-3_8_1\icu
    C:\>d:
    D:\>cd src\boost\boost_1_35_0
    D:\src\boost\boost_1_35_0>bjam -sHAVE_ICU=1 --toolset=msvc stage --build-type=complete

    D:\src\boost\boost_1_35_0>bjam -sHAVE_ICU=1 --toolset=msvc --with-python --build-type=complete stage

    Note: boost.python does not work with python 3.0.

    build boost.mpi

    Install MPICH2 1.0.7 Windows Binary from here;

    update include and lib environment variables;

    add some lines to boost\tools\build\v2\user-config.jam:

    using mpi : : <find-shared-library>cxx
                  <find-shared-library>mpi
                  <library-path>C:/ENV/MPICH2/lib ;

    run build command: D:\src\boost\boost_1_35_0>bjam --toolset=msvc --with-mpi --build-type=complete stage

    another build command style: D:\opensource\boost\boost_1_35_0>bjam --toolset=msvc -sPYTHON_ROOT=c:\python25 -sPYTHON_VERSION=2.5 --build-type=complete stage

    gcc -Wl,--subsystem,windows -mwindows options

    -Wl,--subsystem,windows passes `--subsystem windows' to the linker.  
    -mwindows is a compiler option.
    "it seems that if you use -mwindows you shouldn't need to also use
    -Wl,--subsystem,windows, since that will happen anyhow..."
    from Ian
    February 22

    Hacking class definition

    Once I was asked a question: how to avoid duplicating virtual method declaration in both base class and derived classes? Because there are more than 100 pure virtual functions he has to copy to every derived class. My first answer is using MACRO to expand method declaration, but it is not very realistic and it may hit limitation of compiler -- the line would become too long. Today I suddenly remembered the fact that #include statement just copy files into the compilation unit, so some stuff can be put into a header file and be included inside class declaration, like the following example.

    // begin of sharedbase.h
    // This header file can't be used as standalone, it is meaned to be
    // embedded in class declaration.

    #ifndef PURE_VIRTUAL_PLACE_HOLDER
    #define PURE_VIRTUAL_PLACE_HOLDER
    #define REMOVE_VIRTUAL_PALCE_HOLDER
    #endif

    virtual void method1()    PURE_VIRTUAL_PLACE_HOLDER;
    virtual void method2() PURE_VIRTUAL_PLACE_HOLDER;

    #ifdef REMOVE_VIRTUAL_PALCE_HOLDER
    #undef REMOVE_VIRTUAL_PALCE_HOLDER
    #undef PURE_VIRTUAL_PLACE_HOLDER
    #endif
    // end of sharedbase.h

     

    // begin of base.h
    class Base2
    {
    public:
    #undef PURE_VIRTUAL_PLACE_HOLDER
    #define PURE_VIRTUAL_PLACE_HOLDER =0
    #include "sharedbase.h"
    #undef PURE_VIRTUAL_PLACE_HOLDER
    };

    class Derived2A : public Base2
    {
    public:
    #include "sharedbase.h"
    };

    class Derived2B : public Base2
    {
    public:
    #include "sharedbase.h"
    };

    // end of base.h

     

    #include "base.h"
    #include <iostream>

    void Derived2A::method1()
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    void Derived2A::method2()
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    void Derived2B::method1()
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    void Derived2B::method2()
    {
        std::cout << __FUNCTION__ << std::endl;
    }

    int _tmain(int argc, _TCHAR* argv[])
    {
        Derived2A obj2a;

        return 0;
    }

    January 16

    #import directive cause internal compiler error in VC6

    There is a #import directive in stdafx.h beneath declaration of a class which is derived from CComModule. VC6 always reports internal compiler error on source files that includes this stdafx.h, but VC++ 2005 is OK. The trick for VC6 is to move #import directive above declaration of the class.

    July 29

    local static object initialization is not thread safe and also compiler dependent

    There is already a post
    (http://blogs.msdn.com/oldnewthing/archive/2004/03/08/85901.aspx) on the
    not thread safe aspect. When I am preparing a demo of Loki to someone, I
    found that it was also compiler dependent.
    VC++ 2005 is likely only initialize the object once, but the second
    thread will access uninitialized data; but gcc 3.4.4 will double
    initialize the object. Code snippet is presented here:
    // Demonstrate static object problem in multithread environment.
    // Compiler: VC++ 2005 / Cygwin (gcc 3.4.4)
    // Loki 0.16
    // boost 1.33.1
    // Author: Onega

    #define LOKI_CLASS_LEVEL_THREADING

    #include <loki/Singleton.h>
    #include <loki/threads.h>
    #include <iostream>
    #include <sstream>
    #include <iomanip>
    #include <process.h>
    #include <boost/thread.hpp>

    void MySleep(int seconds)
    {
    boost::xtime t;
    boost::xtime_get(&t, boost::TIME_UTC);
    t.sec += seconds;
    boost::thread::sleep(t);
    }

    class MyClass2
    {
    public:
    MyClass2()
    { // will be called twice when compiled by cygwin, thus memory
    leakage with m_data
    // will be called once when compiled by VC++ 2005, thus memory
    access violation with m_data
    // in one thread.
    MySleep(1);
    m_data = new int;
    boost::xtime t;
    boost::xtime_get(&t, boost::TIME_UTC);
    *m_data = t.sec;
    std::stringstream ss;
    ss << __FUNCTION__
    << ", this = " << std::hex << std::internal << (long)this
    << ", m_date = " << (long)m_data
    << ", GetData() = " << std::dec << GetData()
    << std::endl;
    std::cout << ss.str();
    }
    ~MyClass2()
    {
    std::stringstream ss;
    ss << typeid(*this).name()
    //<< ", in thread:" << GetCurrentThreadId()
    << ", this = " << std::hex << std::internal << (long)this
    << std::endl;
    std::cout << ss.str();
    }
    int* m_data;
    int GetData()
    {
    return *m_data;
    }
    };

    MyClass2& GetUnsafeSingleInst()
    {
    static MyClass2 obj;
    return obj;
    }


    void unsafe_static_demo_thread1()
    {
    std::stringstream ss;
    try
    {
    int data = GetUnsafeSingleInst().GetData(); // memory access
    violation in VC++ 2005
    ss << __FUNCTION__ << " data = " << data << std::endl;
    }
    catch (...)
    {
    ss << __FUNCTION__ << " Exception occurred!" << std::endl;
    }
    std::cout << ss.str();
    }

    void safe_static_demo_thread()
    {
    typedef Loki::SingletonHolder<MyClass2, Loki::CreateStatic,
    Loki::DefaultLifetime, Loki::ClassLevelLockable> SingleMyClass2;
    int data = SingleMyClass2::Instance().GetData();
    std::stringstream ss;
    ss << __FUNCTION__ << " data = " << data << std::endl;
    std::cout << ss.str();

    }

    int main(int argc, char* argv[])
    {

    boost::thread_group g;
    g.create_thread(&safe_static_demo_thread);
    g.create_thread(&safe_static_demo_thread);
    g.create_thread(&unsafe_static_demo_thread1);
    g.create_thread(&unsafe_static_demo_thread1);
    g.join_all();
    MySleep(20);
    return 0;
    }




    July 25

    undefined reference to _IID_IUnknown in cygwin

    I have already added uuid to linker library list, the linker does not complain on uuid. But the problem is fixed by adding libuuid.a to library list.
    At last it turned out to be caused by order of libraries. After I reordered libraries in Code::Blocks, the build is successful.
    -------------- Build: Win32 Release in wx1 ---------------
    [100.0%] g++.exe -L../../wxWidgets-2.8.4/gcc-lib/lib/ -LH:/tmp/boost/bin.v2/libs/filesystem/build/gcc-3.4.4/release/link-static/threading-multi/ -Lh:/cygwin/lib  -o ./Release/wx1.exe Release/CopyThread.o Release/DeleteThread.o Release/mydlg.o Release/ConfigPage.o    -lwx_msw-2.8 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lodbccp32 -loleaut32 -lcomctl32 -lshlwapi -lkernel32 -luser32 -lgdi32 -lexpat -luuid -lcomctl32 -lole32 -lboost_filesystem-gcc34-mt-1_34  -mwindows
    Process terminated with status 0 (0 minutes, 2 seconds)
    0 errors, 0 warnings
    July 22

    Code::Blocks

    Imported a VC++ project into Code::Blocks, and changed the compiler to gcc (MingW). Code::Blocks does not change compiling flags and linking options accurately. Some VC++ flags are imported directly, however they are not applicable to gcc. After some efforts I managed to built it in CB successfully, but the binary does not work -- first error is _impure_ptr problem with cygwin1.dll, after cygwin is updated, the application exited with fatal error -The application failed to initialize properly (0xc0000005).
    After rebuilding wxWidgets many times, my application working correctly now.
    I created static library of wxWidgets and linked to my project.
    Build wxWidgets-2.8.4
    onega.zhang@a0067759 /cygdrive/i/wxWidgets-2.8.4/gcc-lib
    $ ../configure --with-expat --enable-monolithic --with-msw --with-regex --without-subdirs
      --enable-shared=no  --enable-stl --enable-mediactrl   --enable-controls --enable-dataviewctrl
     --enable-tabdialog
    onega.zhang@a0067759 /cygdrive/i/wxWidgets-2.8.4/gcc-lib
    $ make