美文网首页
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