美文网首页
C++性能优化详解《字符串》代码勘误

C++性能优化详解《字符串》代码勘误

作者: FredricZhu | 来源:发表于2022-01-14 19:51 被阅读0次

    作者自己写了一个状态机和一个函数指针做TestDriver。但是只能支持Windows,在Linux上无法运行。而且代码中有多处错误。状态机代码也有错误。
    修改了一下使其能在Linux上运行。
    代码结构如下,


    image.png

    CMakeLists.txt

    cmake_minimum_required(VERSION 2.6)
    
    if(APPLE)
        message(STATUS "This is Apple, do nothing.")
        set(CMAKE_MACOSX_RPATH 1)
        set(CMAKE_PREFIX_PATH /Users/aabjfzhu/software/vcpkg/ports/cppwork/vcpkg_installed/x64-osx/share )
    elseif(UNIX)
        message(STATUS "This is linux, set CMAKE_PREFIX_PATH.")
        set(CMAKE_PREFIX_PATH /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/share)
    endif(APPLE)
    
    set(Boost_NO_WARN_NEW_VERSIONS 1)
    
    project(optimize)
    
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    add_definitions(-g)
    
    find_package(ZLIB)
    
    find_package(glog REQUIRED)
    
    find_package(re2 REQUIRED)
    
    find_package(OpenCV REQUIRED )
    
    find_package(OpenSSL REQUIRED)
    
    find_package(Arrow CONFIG REQUIRED)
    
    find_package(unofficial-brotli REQUIRED)
    
    find_package(unofficial-utf8proc CONFIG REQUIRED)
    find_package(Thrift CONFIG REQUIRED)
    
    find_package(Boost REQUIRED COMPONENTS
        system
        filesystem
        serialization
        program_options
        thread
        )
    
    find_package(DataFrame REQUIRED)
    
    if(APPLE)
        MESSAGE(STATUS "This is APPLE, set INCLUDE_DIRS")
    set(INCLUDE_DIRS ${Boost_INCLUDE_DIRS} /usr/local/include /usr/local/iODBC/include /opt/snowflake/snowflakeodbc/include/ ${CMAKE_CURRENT_SOURCE_DIR}/../include/ ${CMAKE_CURRENT_SOURCE_DIR}/../../../include)
        set(ARROW_INCLUDE_DIR /Users/aabjfzhu/software/vcpkg/ports/cppwork/vcpkg_installed/x64-osx/include)
    elseif(UNIX)
        MESSAGE(STATUS "This is linux, set INCLUDE_DIRS")
        set(INCLUDE_DIRS ${Boost_INCLUDE_DIRS} /usr/local/include ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/../include /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/include)
        set(ARROW_INCLUDE_DIR /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/include)
    endif(APPLE)
    
    
    if(APPLE)
        MESSAGE(STATUS "This is APPLE, set LINK_DIRS")
        set(LINK_DIRS /usr/local/lib /usr/local/iODBC/lib /opt/snowflake/snowflakeodbc/lib/universal /Users/aabjfzhu/software/vcpkg/ports/cppwork/vcpkg_installed/x64-osx/lib)
    elseif(UNIX)
        MESSAGE(STATUS "This is linux, set LINK_DIRS")
        set(LINK_DIRS ${Boost_INCLUDE_DIRS} /usr/local/lib /vcpkg/ports/cppwork/vcpkg_installed/x64-linux/lib)
    endif(APPLE)
    
    if(APPLE)
        MESSAGE(STATUS "This is APPLE, set ODBC_LIBS")
        set(ODBC_LIBS iodbc iodbcinst)
    elseif(UNIX)
        MESSAGE(STATUS "This is linux, set ODBC_LIBS")
        set(ODBC_LIBS odbc odbcinst ltdl)
    endif(APPLE)
    
    include_directories(${INCLUDE_DIRS})
    LINK_DIRECTORIES(${LINK_DIRS})
    
    file( GLOB test_file_list ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) 
    
    file( GLOB APP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../include/http/impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../include/yaml/impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../include/df/impl/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../include/death_handler/impl/*.cpp)
    
    add_library(${PROJECT_NAME}_lib SHARED ${APP_SOURCES} ${test_file})
    target_link_libraries(${PROJECT_NAME}_lib ${Boost_LIBRARIES} ZLIB::ZLIB glog::glog DataFrame::DataFrame ${OpenCV_LIBS})
    target_link_libraries(${PROJECT_NAME}_lib OpenSSL::SSL OpenSSL::Crypto libgtest.a pystring libyaml-cpp.a libgmock.a ${ODBC_LIBS} libnanodbc.a pthread dl backtrace libzstd.a libbz2.a libsnappy.a re2::re2 parquet lz4 unofficial::brotli::brotlidec-static unofficial::brotli::brotlienc-static unofficial::brotli::brotlicommon-static utf8proc thrift::thrift arrow arrow_dataset)
    
    foreach( test_file ${test_file_list} )
        file(RELATIVE_PATH filename ${CMAKE_CURRENT_SOURCE_DIR} ${test_file})
        string(REPLACE ".cpp" "" file ${filename})
        add_executable(${file}  ${test_file})
        target_link_libraries(${file} ${PROJECT_NAME}_lib)
    endforeach( test_file ${test_file_list})
    

    strings_test.cpp

    #include "test_driver.h"
    #include "stopwatch11.h"
    #include <cstdlib>
    #include <string>
    #include <iostream>
    #include <cstring>
    
    
    // original, naive remove_ctrl()
    std::string remove_ctrl(std::string s) {
        std::string result;
        for (size_t i=0; i<s.length(); ++i) {
            if (s[i] >= 0x20)
                result = result + s[i];
        }
        return result;
    }
    
    // remove_ctrl() with operator replaced by mutating assignment
    std::string remove_ctrl_mutating(std::string s) {
        std::string result;
        for (size_t i=0; i<s.length(); ++i) {
            if (s[i] >= 0x20)
                result += s[i];
        }
        return result;
    }
    std::string remove_ctrl_mutating_it(std::string s) {
        std::string result;
        for (auto it=s.begin(); it != s.end(); ++it) {
            if (*it >= 0x20)
                result += *it;
        }
        return result;
    }
    
    std::string remove_ctrl_mutating_it_end(std::string s) {
        std::string result;
        for (auto it=s.begin(),end=s.end();it != end; ++it) {
            if (*it >= 0x20)
                result += *it;
        }
        return result;
    }
    
    // remove_ctrl_mutating() with space reserved in result
    std::string remove_ctrl_reserve(std::string s) {
        std::string result;
        result.reserve(s.length());
        for (size_t i=0; i<s.length(); ++i) {
            if (s[i] >= 0x20)
                result += s[i];
        }
        return result;
    }
    std::string remove_ctrl_reserve_it(std::string s) {
        std::string result;
        result.reserve(s.length());
        for (auto it=s.begin(),end=s.end();it != end; ++it) {
            if (*it >= 0x20)
                result += *it;
        }
        return result;
    }
    
    // remove_ctrl_reserve() with reference arg instead of value arg
    std::string remove_ctrl_refs(std::string const& s) {
        std::string result;
        result.reserve(s.length());
        for (size_t i=0; i<s.length(); ++i) {
            if (s[i] >= 0x20)
                result += s[i];
        }
        return result;
    }
    
    // remove_ctrl_reserve() with reference arg instead of value arg
    std::string remove_ctrl_refs_it(std::string const& s) {
        std::string result;
        result.reserve(s.length());
        for (auto it=s.begin(),end=s.end();it != end; ++it) {
            if (*it >= 0x20)
                result += *it;
        }
        return result;
    }
    
    // remove_ctrl_refs() with reference return value
    void remove_ctrl_ref_result(
        std::string& result,
        std::string const& s) {
        result.clear();
        result.reserve(s.length());
        for (size_t i=0; i<s.length(); ++i) {
            if (s[i] >= 0x20)
                result += s[i];
        }
    }
    
    // remove_ctrl_ref_ret with iterators
    void remove_ctrl_ref_result_it(
        std::string& result,
        std::string const& s) {
        result.clear();
        result.reserve(s.length());
        for (auto it=s.begin(),end=s.end();it != end; ++it) {
            if (*it >= 0x20)
                result += *it;
        }
    }
    
    // remove_ctrl_ref_result() done with buffers instead of strings
    void remove_ctrl_cstrings(char* destp, char const* sourcep, size_t length) {
        for (size_t i=0; i<length; ++i) {
            if (sourcep[i] >= 0x20)
                *destp++ = sourcep[i];
        }
        *destp = 0;
    }
    
    //  copy whole substrings to reduce allocations
    std::string remove_ctrl_block(std::string s) {
        std::string result;
        for (size_t b=0,i=b,e=s.length(); b < e; b = i+1) {
            for (i=b; i<e; ++i) {
                if (s[i] < 0x20) break;
            }
            result = result + s.substr(b,i-b);
        }
        return result;
    }
    
    // remove_ctrl_block() with mutating concatenation, reserved size
    std::string remove_ctrl_block_mutate(std::string s) {
        std::string result;
        result.reserve(s.length());
        for (size_t b=0,i=b,e=s.length(); b < e; b = i+1) {
            for (i=b; i<e; ++i) {
                if (s[i] < 0x20) break;
            }
            result += s.substr(b,i-b);
        }
        return result;
    }
    
    std::string remove_ctrl_block_append(std::string s) {
        std::string result;
        result.reserve(s.length());
        for (size_t b=0,i=b; b < s.length(); b = i+1) {
            for (i=b; i<s.length(); ++i) {
                if (s[i] < 0x20) break;
            }
            result.append(s, b, i-b);
        }
        return result;
    }
    
    std::string remove_ctrl_block_append_it(std::string s) {
        std::string result;
        result.reserve(s.length());
        for (auto b=s.begin(),i=b; b != s.end(); b = i+1) {
            for (i=b; i != s.end(); ++i) {
                if (*i < 0x20) break;
            }
            result.append(b, i);
        }
        return result;
    }
    
    std::string remove_ctrl_block_append_cache(std::string s) {
        std::string result;
        result.reserve(s.length());
        for (size_t b=0,i=b,e=s.length(); b < e; b = i+1) {
            for (i=b; i<e; ++i) {
                if (s[i] < 0x20) break;
            }
            result.append(s, b, i-b);
        }
        return result;
    }
    
    std::string remove_ctrl_block_append_cache_it(std::string s) {
        std::string result;
        result.reserve(s.length());
        for (auto b=s.begin(),i=s.begin(),e=s.end(); b != e; b = i+1) {
            for (i=b; i != e; ++i) {
                if (*i < 0x20) break;
            }
            result.append(b, i);
        }
        return result;
    }
    
    // remove_ctrl_block_mutate() with reference arg
    std::string remove_ctrl_blocks(std::string const& s) {
        std::string result;
        result.reserve(s.length());
        for (size_t b=0,i=b,e=s.length(); b < e; b = i+1) {
            for (i=b; i<e; ++i) {
                if (s[i] < 0x20) break;
            }
            result.append(s, b,i-b);
        }
        return result;
    }
    //  remove_ctrl_blocks() with reference return value
    void remove_ctrl_block_ret(std::string& result, std::string const& s) {
        result.clear();
        result.reserve(s.length());
        for (size_t b=0,i=b,e=s.length(); b < e; b = i+1) {
            for (i=b; i<e; ++i) {
                if (s[i] < 0x20) break;
            }
            result.append(s, b, i-b);
        }
    }
    
    void remove_ctrl_block_ret_it(std::string& result, std::string const& s) {
        result.clear();
        result.reserve(s.length());
        for (auto b=s.begin(),i=b,e=s.end(); b != e; b = i+1) {
            for (i=b; i != e; ++i) {
                if (*i < 0x20) break;
            }
            result.append(b, i);
        }
    }
    
    //  cleverly reduce the size of a string so it doesn't have to be reallocated
    std::string remove_ctrl_erase(std::string s) {
        for (size_t i = 0; i < s.length(); ) 
            if (s[i] < 0x20)
                s.erase(i,1);
            else ++i;
        return s;
    }
    std::string remove_ctrl_erase_it(std::string s) {
        for (auto i = s.begin(); i != s.end(); ) 
            if (*i < 0x20)
                s.erase(i);
            else ++i;
        return s;
    }
    
    int test_strings(int test_no, unsigned long multiplier) {
        typedef unsigned counter_t;
        counter_t iterations = 1000*multiplier;
    
        std::string s("\07Now is the time\07 for all good men\r\n to come to the aid of their country. \07");
        std::string test("Now is the time for all good men to come to the aid of their country. ");
        std::string result;
        s = s + s + s;
        test = test + test + test;
    
        bool rc = true;
    
        switch (test_no) {
        default: return -1;
        case 0:  return 12;
        case 1:
    #       if defined _WIN32
    #           if defined _DEBUG
                    std::cout << "Windows debug build" << std::endl;
    #           else
                    std::cout << "Windows release build" << std::endl;
    #           endif
    #       else
                std::cout << "Linux build" << std::endl;
    #       endif   
            std::cout << s.length() << " character argument to remove_ctrl()" << std::endl;
            std::cout << iterations << " iterations" << std::endl;
            result = remove_ctrl(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_mutating(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_mutating_it(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_reserve(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_reserve_it(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_refs(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_refs_it(s);
            rc &= (result.compare(test) == 0);
            remove_ctrl_ref_result(result, s);
            rc &= (result.compare(test) == 0);
            remove_ctrl_ref_result_it(result, s);
            rc &= (result.compare(test) == 0);
            {
                char a[1000]; 
                memset(a, 0, sizeof(a));
                remove_ctrl_cstrings(a, s.data(), s.length());
                rc &= (strcmp(a, test.data()) == 0);
    //            memset(a, 0, sizeof(a));
    //            remove_ctrl_6(a, s.data(), s.length());
    //            rc &= (strcmp(a, test.data()) == 0);
            }
            result = remove_ctrl_block(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_block_mutate(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_block_append(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_block_append_it(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_block_append_cache(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_block_append_cache_it(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_blocks(s);
            rc &= (result.compare(test) == 0);
            remove_ctrl_block_ret(result, s);
            rc &= (result.compare(test) == 0);
            remove_ctrl_block_ret(result, s);
            rc &= (result.compare(test) == 0);
            remove_ctrl_block_ret_it(result, s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_erase(s);
            rc &= (result.compare(test) == 0);
            result = remove_ctrl_erase_it(s);
            rc &= (result.compare(test) == 0);
            break;
    
        case 2:
            {
                Stopwatch sw("remove_ctrl()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl(s);
            }
            rc &= (result.compare(test) == 0);
            break;
    
        case 3: 
            {   Stopwatch sw("remove_ctrl_mutating()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_mutating(s);
            }
            rc &= (result.compare(test) == 0);
            {   Stopwatch sw("remove_ctrl_mutating_it()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_mutating_it(s);
            }
            rc &= (result.compare(test) == 0);
            {   Stopwatch sw("remove_ctrl_mutating_it_end()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_mutating_it_end(s);
            }
            rc &= (result.compare(test) == 0);
            break;
    
        case 4: 
            {   Stopwatch sw("remove_ctrl_reserve()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_reserve(s);
            }
            rc &= (result.compare(test) == 0);
            {   Stopwatch sw("remove_ctrl_reserve_it()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_reserve_it(s);
            }
            rc &= (result.compare(test) == 0);
            break;
    
        case 5: 
            {   Stopwatch sw("remove_ctrl_refs()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_refs(s);
            }
            rc &= (result.compare(test) == 0);
            {   Stopwatch sw("remove_ctrl_refs_it()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_refs_it(s);
            }
            rc &= (result.compare(test) == 0);
            break;
    
        case 6: 
            {   Stopwatch sw("remove_ctrl_ref_result()");
                for (counter_t i = 0; i < iterations; ++i)
                    remove_ctrl_ref_result(result, s);
            }
            rc &= (result.compare(test) == 0);
            {   Stopwatch sw("remove_ctrl_ref_it()");
                for (counter_t i = 0; i < iterations; ++i)
                    remove_ctrl_ref_result_it(result, s);
            }
            rc &= (result.compare(test) == 0);
            break;
    
        case 7: {
                Stopwatch sw("remove_ctrl_cstrings()");
                for (counter_t i = 0; i < iterations; ++i) {
                    char a[1000];
                    remove_ctrl_cstrings(a, s.data(), s.length());
                }
            }
            rc &= (result.compare(test) == 0);
            break;
    
        case 8: {
                Stopwatch sw("remove_ctrl_block()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_block(s);
            }
            rc &= (result.compare(test) == 0);
            break;
    
        case 9: 
            {   Stopwatch sw("remove_ctrl_block_mutate()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_block_mutate(s);
            }
            rc &= (result.compare(test) == 0);
            {   Stopwatch sw("remove_ctrl_block_append()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_block_append(s);
            }
            rc &= (result.compare(test) == 0);
            {   Stopwatch sw("remove_ctrl_block_append_it()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_block_append_it(s);
            }
            rc &= (result.compare(test) == 0);
            {   Stopwatch sw("remove_ctrl_block_append_cache()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_block_append_cache(s);
            }
            rc &= (result.compare(test) == 0);
            {   Stopwatch sw("remove_ctrl_block_append_cache_it()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_block_append_cache_it(s);
            }
            rc &= (result.compare(test) == 0);
            break;
    
        case 10: {
                Stopwatch sw("remove_ctrl_blocks()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_blocks(s);
            }
            rc &= (result.compare(test) == 0);
            break;
    
        case 11: 
            {    Stopwatch sw("remove_ctrl_block_ret()");
                for (counter_t i = 0; i < iterations; ++i)
                    remove_ctrl_block_ret(result, s);
            }
            rc &= (result.compare(test) == 0);
            {    Stopwatch sw("remove_ctrl_block_ret_it()");
                for (counter_t i = 0; i < iterations; ++i)
                    remove_ctrl_block_ret_it(result, s);
            }
            rc &= (result.compare(test) == 0);
            break;
    
        case 12:
            {   Stopwatch sw("remove_ctrl_erase()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_erase(s);
            }
            rc &= (result.compare(test) == 0);
            {   Stopwatch sw("remove_ctrl_erase_it()");
                for (counter_t i = 0; i < iterations; ++i)
                    result = remove_ctrl_erase_it(s);
            }
            rc &= (result.compare(test) == 0);
            break;
        }
        return rc ? 1 : 0;
    }
    
    int main(int argc, char* argv[]) {
        test_driver(test_strings, argc, argv);
        return EXIT_SUCCESS;
    }
    

    include/test_driver.h

    #ifndef _FREDRIC_TEST_DRIVER_H_
    #define _FREDRIC_TEST_DRIVER_H_
    
    typedef int (*testfunc)(int, unsigned long);
    void test_driver(testfunc* flist, int argc=0, char** argv=0);
    void test_driver(testfunc f, int argc=0, char** argv=0);
    
    #endif
    

    include/stop_watch.h

    #ifndef STOPWATCH_H
    #define STOPWATCH_H
    #include <iostream>
    
    /*  class Stopwatch -- simple stopwatch timer for optimization
    
        Stopwatch prints out elapsed time information for measuring the run time
        of long-running tasks. Stopwatch can also return the elapsed time without
        printing anything.
    
        Stopwatch is meant to be used with the RAII idiom. In its
        simplest use, the block
    
            {
                Stopwatch sw("TheThing()");
                TheThing();
            }
    
        produces two lines of output like
    
            TheThing(): start
            // anything printed by TheThing()
            TheThing(): stop 63mS
    
        Stopwatch is meant to replace something more complex like
    
        {
            timeval t1, t2;
            long dt;
            gettimeofday(&t1, NULL);
            TheThing();
            gettimeofday(&t2, NULL);
            dt = (t2.tv_sec * 1000000 + t2.tv_usec) - (t1.tv_sec * 1000000 + t1.tv_usec);
            std::cout << "TheThing() took " << dt/1000 << " mS" << std::endl;
        }
    
        What it prints
            ctor():                         "Stopwatch: start"
            ctor(false):                    nothing printed
            Show():                         "Stopwatch: show at xxxx mS"
                                            sets lap time. Get with LapGet()
            Stop():                         "Stopwatch: stop xxxx mS"
                                            sets lap time. Get with LapGet()
            Stop() when not running:        "Stopwatch: not started"
            Start():                        "Stopwatch: start"
                                            clears lap time
            Start() when running:           "Stopwatch: start xxxx mS"
                                            sets lap time. Get with LapGet()
        What it prints when activity name is specified
            ctor("activity"):               "activity: start"
            Show("theEvent"):               "activity: theEvent at xxxx mS"
            Stop("theEvent"):               "activity: theEvent xxxx mS"
                                            sets lap time. Get with LapGet()
            Stop("theEvent") not running:   "activity: not started"
            Start("theEvent") running:      "activity: theEvent xxxx mS"
                                            sets lap time. Get with LapGet()
            Start("theEvent") not running: "activity: theEvent"
                                            clears lap time
    
        printing can be suppressed (get time using LapGet()
            ctor("") or ctor(nullptr)       prints nothing
            Show("") or Show(nullptr)       prints nothing, sets lap time
            Start("") or Start(nullptr):    prints nothing, sets lap time if running
            Stop("") or Stop(nullptr):      sets lap time. Get with LapGet()
    */
    
    template <typename T> class basic_stopwatch : public T {
    public:
        typedef T BaseTimer;
        typedef typename T::tick_t tick_t;
    
        // create, optionally start timing an activity
        explicit basic_stopwatch(bool start);
        explicit basic_stopwatch(char const* activity = "Stopwatch",
                                 bool start=true);
        basic_stopwatch(std::ostream& log,
                        char const* activity="Stopwatch", 
                        bool start=true); 
    
        // stop and destroy a stopwatch
        ~basic_stopwatch();
    
        // get last lap time (time of last stop)
        tick_t LapGet() const;
    
        // predicate: return true if the stopwatch is running
        bool IsStarted() const;
    
        // show accumulated time, keep running, set/return lap
        tick_t Show(char const* event="show");
    
        // (re)start a stopwatch, set/return lap time
        tick_t Start(char const* event_namee="start");
    
        // stop a running stopwatch, set/return lap time
        tick_t Stop(char const* event_name="stop");
    
    private:    //  members
        char const*     m_activity; // "activity" string
        tick_t          m_lap;      // lap time (time of last stop or 0)
        std::ostream&   m_log;      // stream on which to log events
    };
    
    //  performs a Start() if start_now == true
    template <typename T> inline basic_stopwatch<T>::basic_stopwatch(bool start_now)
      : m_activity("Stopwatch")
      , m_lap(0)
      , m_log(std::cout) 
    {
        if (start_now)
            Start();
    }
    
    //  performs a start if start_now == true, suppress print by ctor("")
    template <typename T> inline basic_stopwatch<T>::basic_stopwatch(char const* activity, bool start_now)
      : m_activity(activity && activity[0] ? activity : nullptr)
      , m_lap(0)
      , m_log(std::cout) 
    {
        if (start_now) {
            if (m_activity)
                Start();
            else
                Start(nullptr);
        }
    }
    
    //  set log output, optional printout, optional start
    template <typename T> inline basic_stopwatch<T>::basic_stopwatch(std::ostream& log, char const* activity, bool start_now)
      : m_activity(activity && activity[0] ? activity : nullptr)
      , m_lap(0)
      , m_log(log) 
    {
        if (start_now) {
            if (m_activity)
                Start();
            else
                Start(nullptr);
        }
    }
    
    //  stop/destroy stopwatch, print message if activity was set in ctor
    template <typename T> inline basic_stopwatch<T>::~basic_stopwatch() {
        if (IsStarted()) {
            if (m_activity)
                Stop();
            else
                Stop(nullptr);
        }
    }
    
    //   predicate: return true if the stopwatch is running
    template <typename T> inline bool basic_stopwatch<T>::IsStarted() const
    {
        return BaseTimer::IsStarted();
    }
    
    //  get the last lap time (time of last stop)
    template <typename T> inline typename basic_stopwatch<T>::tick_t basic_stopwatch<T>::LapGet() const
    {
        return m_lap;
    }
    
    //   show accumulated time, keep running, get/return lap time
    template <typename T> inline typename basic_stopwatch<T>::tick_t basic_stopwatch<T>::Show(char const* event_name) {
        if (IsStarted()) {
            m_lap = BaseTimer::GetMs();
            if (event_name && event_name[0]) {
                if (m_activity)
                    m_log << m_activity << ": ";
                m_log << event_name << " at " << m_lap << "mS" << std::endl << std::flush;
            }
        }
        else {
            if (m_activity)
                m_log << m_activity << ": not started" << std::endl << std::flush;
        }
        return m_lap;
    }
    
    //   (re)start a stopwatch, set/return lap time
    template <typename T> inline typename basic_stopwatch<T>::tick_t basic_stopwatch<T>::Start(char const* event_name) {
        if (IsStarted()) {
            Stop(event_name);
        }
        else {
            if (event_name && event_name[0]) {
                if (m_activity)
                    m_log << m_activity << ": ";
                m_log << event_name << std::endl << std::flush;
            }
        }
        BaseTimer::Start();
        return m_lap;
    }
    
    //   stop a running stopwatch and print the accumulated time
    template <typename T> inline typename basic_stopwatch<T>::tick_t basic_stopwatch<T>::Stop(char const* event_name) {
        if (IsStarted()) {
            m_lap = BaseTimer::GetMs();
            if (event_name && event_name[0]) {
                if (m_activity)
                    m_log << m_activity << ": ";
                m_log << event_name << " " << m_lap << "mS" << std::endl << std::flush;
            }
        }
        BaseTimer::Clear();
        return m_lap;
    }
    # endif
    

    include/stopwatch11.h

    #ifndef STOPWATCH11_H
    #define STOPWATCH11_H
    
    #include <chrono>
    
        using namespace std::chrono;
        class TimerBaseChrono {
    
        public:
            typedef unsigned long tick_t;
            //  clears the timer
            TimerBaseChrono() : m_start(system_clock::time_point::min()) { }
    
            //  clears the timer
            void Clear() { 
                m_start = system_clock::time_point::min(); 
            }
    
            //  returns true if the timer is running
            bool IsStarted() const {
                return (m_start != system_clock::time_point::min());
            }
    
            //  start the timer
            void Start()            { m_start = std::chrono::system_clock::now(); }
    
            //  get the number of milliseconds since the timer was started
            unsigned long GetMs() {
                if (IsStarted()) {
                    system_clock::duration diff;
                    diff = system_clock::now() - m_start;
                    return (unsigned)(duration_cast<milliseconds>(diff).count());
                }
                return 0;
            }
        private:
            std::chrono::system_clock::time_point m_start;
        }; 
    
    #include "stopwatch.h"
    typedef basic_stopwatch<TimerBaseChrono> Stopwatch;
    
    # endif
    

    include/priority_thread.h

    #ifndef _PRIORITY_THREAD_H_
    #define _PRIORITY_THREAD_H_
    #include <unistd.h>
    #include <pthread.h>
    
    struct PriorityThread {
        int policy;
        int old_priority;
        sched_param param;
        PriorityThread();
       ~PriorityThread();
    };
    
    #endif
    

    impl/priority_thread.cpp

    #include "priority_thread.h"
    
    #include <iostream>
    
    PriorityThread::PriorityThread() {
        // 设置当前进程nice值为最低,设为最高优先级进程
        nice(-20);
        // 获取当前优先级
        pthread_getschedparam(pthread_self(), &policy, &param); 
        old_priority = param.sched_priority;
        // 设置当前线程优先级为最高优先级
        param.sched_priority = sched_get_priority_max(policy);
        pthread_setschedparam(pthread_self(), policy, &param);
    }
    
    PriorityThread::~PriorityThread() {
        // 设置当前进程nice值为最高,降低优先级
        nice(19);
        // 设置优先级为普通线程优先级
        param.sched_priority = old_priority;
        pthread_setschedparam(pthread_self(), policy, &param);
    }
    

    impl/stopwatch11.cpp

    # include "stopwatch11.h"
    # include <thread>
    
    void Sleep(unsigned ms)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(ms));
    }
    
    int test_stopwatch11(int test_no, unsigned long)
    {
        bool rc = true;
        switch (test_no)
        {
        default:    return -1;
        case 0:     return 4;
        case 1: {
                    TimerBaseChrono tb;
                    tb.Start();
                    Sleep(5);
                    unsigned dt1 = tb.GetMs();
                    Sleep(20);
                    unsigned dt2 = tb.GetMs();
                    Sleep(35);
                    unsigned dt3 = tb.GetMs();
                    break;
                }
    
        case 2: {
                    Stopwatch sw;
                    Sleep(15);
                    unsigned dt1 = sw.Show();
                    rc &= (dt1 == sw.LapGet());
                    rc &= (15 <= dt1 && dt1 <= 32);
                    Sleep(25);
                    unsigned dt2 = sw.Show();
                    rc &= (dt2 == sw.LapGet());
                    rc &= (dt1 + 25 <= dt2 && dt2 <= dt1 + 32);
                    Sleep(15);
                    unsigned dt3 = sw.Stop();
                    rc &= (dt3 == sw.LapGet());
                    rc &= (dt2 + 15 <= dt3 && dt3 <= dt2 + 32);
                    break;
                }
    
        case 3: {
                    Stopwatch sw("timing run", false);
                    Sleep(10);
                    unsigned dt1 = sw.Start();
                    rc &= (dt1 == 0);
                    Sleep(15);
                    unsigned dt2 = sw.Start("event1");
                    rc &= (15 <= dt2 && dt2 <= 32);
                    Sleep(25);
                    unsigned dt3 = sw.Start("event2");
                    rc &= (25 <= dt3 && dt3 <= 32);
                    Sleep(5);
                    unsigned dt4 = sw.Stop("event3");
                    rc &= (5 <= dt4 && dt4 <= 16);
                    break;
                }
    
        case 4: {
                    Stopwatch sw("");
                    Sleep(15);
                    unsigned dt1 = sw.Show("");
                    rc &= (15 <= dt1 && dt1 <= 32);
                    unsigned dt2 = sw.Start("");
                    rc &= (15 <= dt2 && dt2 <= 32);
                    break;
                }
        }// end switch
        return rc ? 1 : 0;
    }
    

    impl/test_driver.cpp

    #include "test_driver.h"
    #include "priority_thread.h"
    
    #include <iostream>
    #include <cstring>
    
    //  os-independent except for PriorityThread
    void test_driver(testfunc* flist, int argc, char** argv)
    {
        unsigned long multiplier = 1;
        if (argc > 1) {
            if (strncmp(argv[1], "-x", 2) == 0)
                multiplier = strtoul(argv[1]+2, nullptr, 10);
        }
        if (flist == nullptr) {
            std::cout << "No test function" << std::endl;
        }
        else {
            std::cout << "multiplier set to " << multiplier << std::endl;
            PriorityThread p;
            for (unsigned f = 0; flist[f] != 0; ++f) {
                if (flist[f] == nullptr)
                    continue;
                if (flist[f](1, multiplier) == 1)
                    std::cout << "All tests pass" << std::endl;
                else
                    std::cout << "tests failed" << std::endl;
    
                for (int i = 2, e = flist[f](0, multiplier); i <= e; ++i)
                    if (flist[f](i, multiplier) != 1)
                        std::cout << "test " << i << " failed" << std::endl;
            }
        }
    }
    
    void test_driver(testfunc f, int argc, char** argv)
    {
        unsigned long multiplier = 1;
        if (argc > 1) {
            if (strncmp(argv[1], "-x", 2) == 0)
                multiplier = strtoul(argv[1]+2, nullptr, 10);
        }
        if (f == nullptr) {
            std::cout << "No test function" << std::endl;
        }
        else {
            std::cout << "multiplier set to " << multiplier << std::endl;
            PriorityThread p;
            if (f(1, multiplier) == 1)
                std::cout << "All tests pass" << std::endl;
            else
                std::cout << "tests failed" << std::endl;
    
            for (int i = 2, e = f(0, multiplier); i <= e; ++i)
                if (f(i, multiplier) != 1)
                    std::cout << "test " << i << " failed" << std::endl;
        }
    }
    

    程序输出如下,


    image.png

    相关文章

      网友评论

          本文标题:C++性能优化详解《字符串》代码勘误

          本文链接:https://www.haomeiwen.com/subject/ouczcrtx.html