C++性能测试工具

news2024/11/25 18:59:12

使用示例main.cpp

// g++-13  -O3  -std=c++17  main.cpp  profile.cpp
#include <iostream>
#include <chrono>
#include <stdint.h>
#include <mutex>       // std::mutex

#include "profile.h"
#include "profile_rdtsc.h"

std::mutex mutex;

uint64_t getTimeHighResolutionClock() {
    return std::chrono::duration_cast<std::chrono::nanoseconds>(
            std::chrono::high_resolution_clock().now().time_since_epoch()).count();
}

void batchMeasureClockOverhead(){
    constexpr int kLoops = 1000;
    uint64_t t1 = rdtsc();
    for (int i = 0; i < kLoops; ++i) {
        getTimeHighResolutionClock();
    }
    uint64_t t2 = rdtsc();
    std::cout << "Batch test, std::chrono::high_resolution_clock() takes " << (t2 - t1) / kLoops << " cycles on average.\n";
}

PROFILE_REGISTER(single_measure_clock_overhead);
void singleMeasureClockOverhead(){
    PROFILE_CHECK(single_measure_clock_overhead);
    getTimeHighResolutionClock();
}

int main() {
    std::cout << "===Begin of main!===\n";

    getTimeHighResolutionClock();   // warm up

    batchMeasureClockOverhead();
    constexpr int kLoops = 1000;
    for (int i = 0; i < kLoops; ++i) {
        // 这里加锁保护,在多线程中使用此工具需更加注意
        std::lock_guard guard{mutex};
        singleMeasureClockOverhead();
    }

    std::cout << "===End of main!===\n";
}

profile.h

#ifndef PROFILER_PROFILE_H
#define PROFILER_PROFILE_H

#include <iostream>
#include <vector>
#include <set>
#include <string>
#include <string_view>
#include <format>
#include <assert.h>

#include "profile_rdtsc.h"

#define PF_DEBUG  // open performance test or not

namespace pf {

    struct ProfileInfo {
        int id_;
        int call_count_;
        uint64_t call_duration_;
        std::string func_name_;
    };

    class Profile {
    private:
        Profile() {
#ifdef PF_DEBUG
            constexpr int kTimes = 16;
            for (int i = 0; i < kTimes; ++i) {
                uint64_t begin = rdtsc_benchmark_begin();
                uint64_t end = rdtsc_benchmark_end();
                if (overhead_ > end - begin) {
                    overhead_ = end - begin;   // maybe not the smallest
                }
            }
#endif
            //std::cout << "Profile ctor called.\n";
        }

        ~Profile() {
#ifdef PF_DEBUG
            std::cout << "---> Performance details begin: <---\n";
            std::cout << "Attention, overhead is " << overhead_
                      << " cycles, and it is removed from average duration.\n";
            for (const auto &item: info_) {
                if (!item.call_count_) {
                    continue;
                }
                double average = static_cast<double>(item.call_duration_) / static_cast<double>(item.call_count_) -
                                 static_cast<double>(overhead_);
                if (average < 0) {
                    average = 0.0;  // time cost is smaller than overhead_, because the overhead_ is not accuracy.
                }
                std::cout << "[" << item.func_name_ << ", called " << item.call_count_ << " times, total duration cycle is "
                          << item.call_duration_ << ", average duration cycle is " << average << ".]" << std::endl;

            }
            std::cout << "---> Performance details end. <---\n";
#endif
        }

        Profile(const Profile &) = delete;

        Profile &operator=(const Profile &) = delete;

    public:
        static Profile &getInstance();

        void addInfo(int id, uint64_t duration) {
            assert(id >= 0 && id < static_cast<int>(info_.size()));
            ++info_[id].call_count_;
            info_[id].call_duration_ += duration;
        }

        int registerFunc(const std::string_view func_name) {
            auto [iter, success] = func_name_.insert(std::string(func_name));
            assert(success && "One function can only be registered once!");
            int func_id = static_cast<int>(info_.size());
            info_.push_back({func_id, 0, 0, *iter});

            return func_id;
        }

    private:
        std::set<std::string> func_name_;
        std::vector<ProfileInfo> info_;
        uint64_t overhead_{~0UL};
    };

    class ProfilingChecker {
    public:
        ProfilingChecker(int id) : id_(id), start_time_(rdtsc_benchmark_begin()) {
            //std::cout << "ProfilingChecker ctor called.\n";
        }

        ~ProfilingChecker() {
            uint64_t end_time = rdtsc_benchmark_end();
            uint64_t duration = end_time - start_time_;
            Profile::getInstance().addInfo(id_, duration);

            //std::cout << "ProfilingChecker dtor called.\n";
        }

        ProfilingChecker(const ProfilingChecker &) = delete;

        ProfilingChecker &operator=(const ProfilingChecker &) = delete;

    private:
        int id_;
        uint64_t start_time_;
    };

    int doProfileRegister(const std::string_view func_name);

#ifdef PF_DEBUG
#define PROFILE_REGISTER(func) static const int _pf_id_##func = pf::doProfileRegister(#func);
#define PROFILE_CHECK(func) pf::ProfilingChecker _checker(_pf_id_##func);
#else
    #define PROFILE_REGISTER(func)
#define PROFILE_CHECK(func)
#endif

#ifdef _MSC_VER
#define PROFILE_NOINLINE __declspec(noinline)
#else
#define PROFILE_NOINLINE __attribute__((noinline))
#endif
}

#endif //PROFILER_PROFILE_H

profile.cpp

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

namespace pf {

    Profile &Profile::getInstance() {
        static Profile instance;
        return instance;
    }

    int doProfileRegister(const std::string_view func_name){
        return Profile::getInstance().registerFunc(func_name);
    }
}

profile_rdtsc.h


#ifndef PROFILE_PROFILE_RDTSC_H
#define PROFILE_PROFILE_RDTSC_H

#include <stdint.h>         // uint64_t

#ifndef HAS_HW_RDTSC
#if defined(_M_X64) || defined(_M_IX86) || defined(__x86_64) || defined(__i386)
#define HAS_HW_RDTSC 1
#else
#define HAS_HW_RDTSC 0
#endif
#endif

#if HAS_HW_RDTSC
#ifdef _WIN32
#include <intrin.h>        // __rdtsc/_mm_lfence/_mm_mfence
#elif __has_include(<x86intrin.h>)
#include <x86intrin.h>     // __rdtsc/_mm_lfence/_mm_mfence
#endif
#else
#include <chrono>          // std::chrono::steady_clock/nanoseconds
#endif

// Macro to forbid the compiler from reordering instructions
#ifdef _MSC_VER
#define RDTSC_MEM_BARRIER() _ReadWriteBarrier()
#else
#define RDTSC_MEM_BARRIER() __asm__ __volatile__("" : : : "memory")
#endif

inline uint64_t rdtsc()
{
    RDTSC_MEM_BARRIER();

#if HAS_HW_RDTSC
    uint64_t result = __rdtsc();
#else
    uint64_t result = std::chrono::steady_clock::now().time_since_epoch() /
                      std::chrono::nanoseconds(1);

    //uint64_t result = std::chrono::high_resolution_clock::now().time_since_epoch() /
    //                  std::chrono::nanoseconds(1);
#endif

    RDTSC_MEM_BARRIER();

    return result;
}

#if HAS_HW_RDTSC

inline uint64_t rdtsc_benchmark_begin()
{
    // memory fence, according to x86 architecture,保障开始测试之前让CPU将之前未执行完的指令执行完
    _mm_mfence();
    _mm_lfence();
    uint64_t result = __rdtsc();
    RDTSC_MEM_BARRIER();
    return result;
}

inline uint64_t rdtsc_benchmark_end()
{
    _mm_lfence();
    uint64_t result = __rdtsc();
    RDTSC_MEM_BARRIER();
    return result;
}

#else

inline uint64_t rdtsc_benchmark_begin()
{
    return rdtsc();
}

inline uint64_t rdtsc_benchmark_end()
{
    return rdtsc();
}

#endif

#endif //PROFILE_PROFILE_RDTSC_H

可能的输出结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1580365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

GlusterFS分布式文件系统

一、GlusterFS简介 GlusterFS 是一个开源的分布式文件系统。由存储服务器、客户端以及NFS/Samba存储网关(可选&#xff0c;根据需要选择使用)组成。没有元数据服务器组件&#xff0c;这有助于提升整个系统的性能、可靠性和稳定性 二、GlusterFS特点 2.1 扩展性和高性能 Glu…

Tensorboard以及Transforms初步学习

一.前情提要 1.本文是代码结合知识点&#xff0c;注释即为知识点 2.主要详细讲解Tensorboard以及Transforms代码以及基础知识 3.若想深入学习&#xff0c;建议阅读 P3. Python学习中的两大法宝函数&#xff08;当然也可以用在PyTorch&#xff09;_哔哩哔哩_bilibili 二.简述…

Scala中如何使用Jsoup库处理HTML文档?

在当今互联网时代&#xff0c;数据是互联网应用程序的核心。对于开发者来说&#xff0c;获取并处理数据是日常工作中的重要一环。本文将介绍如何利用Scala中强大的Jsoup库进行网络请求和HTML解析&#xff0c;从而实现爬取京东网站的数据&#xff0c;让我们一起来探索吧&#xf…

云智慧发布对象关系型数据库CloudPanguDB,打破传统技术壁垒

近日&#xff0c;云智慧推出关系型数据库CloudPanguDB&#xff08;中文名称&#xff1a;盘古数据库&#xff09;&#xff0c;旨在通过高兼容性能和创新技术架构&#xff0c;降低企业项目整体运营成本。 无论是处理海量复杂数据&#xff0c;还是构建清晰有序的数据结构关系&…

c++ 谷歌glog日志库使用

效果如图&#xff1a; 本次使用qt环境演示&#xff0c;相关库文件和头文件下载链接&#xff1a;https://download.csdn.net/download/bangtanhui/89108477 将相关库文件和头文件&#xff0c;丢到工程目录下 然后需要在工程pro文件当中引入库文件和头文件&#xff1a; …

创建型模式--2.简单工厂模式【人造恶魔果实工厂1】

1. 工厂模式的特点 在海贼王中&#xff0c;作为原王下七武海之一的多弗朗明哥&#xff0c;可以说是新世界最大的流氓头子&#xff0c;拥有无上的权利和无尽的财富。他既是德雷斯罗萨国王又是地下世界的中介&#xff0c;控制着世界各地的诸多产业&#xff0c;人造恶魔果实工厂就…

Java Web这一路走来

大部分Java应用都是Web或网络应用&#xff0c;MVC框架在Java框架中有着举足轻重的地位&#xff0c;一开始的Web应用并不现在这样子的&#xff0c;一步一步走来&#xff0c;每一步都经历了无数的血和泪的教训&#xff0c;以史为镜可以知兴替。 1. 草莽时代 早期的Java服务端技…

使用ollydbg还原密码程序的密码

前言&#xff1a;我们上次用ida pro破解了程序密码这次我们换个工具来还原程序密码 第一步 和上次一样把找到的程序拖到ollydbg里面 第二步 右键点击查找所有引用字符串 第三步 找到报错代码双击进入 第五步 找到上面的jnz双击将其改成jz 第六步 将所修改的保存点击空白…

FPGA(Verilog)实现uart传输协议传输数据(含仿真)

目录 实现功能&#xff1a; 1.接收uart串行数据&#xff0c;输出并行数据(1byte)。 2.输入并行数据(1byte)&#xff0c;输出uart串行数据。 3.完成uart传输的1次环回。 uart协议的1帧数据传输 模块封装-port设置 Verilog代码实现 1.uart接收模块:接收串行数据,输出并行数…

基于Java+SpringBoot+Vue企业员工管理系统(源码+文档+部署+讲解)

一.系统概述 随着社会的发展&#xff0c;系统的管理形势越来越严峻。越来越多的用户利用互联网获得信息&#xff0c;但各种信息鱼龙混杂&#xff0c;信息真假难以辨别。为了方便用户更好的获得信息&#xff0c;因此&#xff0c;设计一种安全高效的员工管理系统极为重要。 为设计…

swiftui macOS实现加载本地html文件

import SwiftUI import WebKitstruct ContentView: View {var body: some View {VStack {Text("测试")HTMLView(htmlFileName: "localfile") // 假设你的本地 HTML 文件名为 index.html.frame(minWidth: 100, minHeight: 100) // 设置 HTMLView 的最小尺寸…

【攻防世界】php_rce (ThinkPHP5)

进入题目环境&#xff0c;查看页面信息&#xff1a; 页面提示 ThinkPHP V5&#xff0c;猜测存在ThinkPHP5 版本框架的漏洞&#xff0c;于是查找 ThinkPHP5 的攻击POC。 构造 payload: http://61.147.171.105:50126/?sindex/think\app/invokefunction&functioncall_user_f…

续写Groq

这章写点Groq干货,理性的分析。 首先是Articical Analysis的关于Mixtral8*7B的吞吐比较 上图是有Mixtral 8*7BPaaS服务的AI服务商,Mistral自己居然排倒数第三 ,Groq是真的遥遥领先啊。 另外这个图是比较每100万tokens的cost,无论是推理速度还是cost,Groq都是遥遥领先…

如何把1G多的视频压缩到500兆以内?3个方法轻松减小文件内存~

微信已经成为了我们上班交流沟通时必不可少的通讯工具之一&#xff0c;在使用微信时&#xff0c;常常会遇到系统提示发送的word、ppt、pdf文件、视频、压缩包等文件超过1G&#xff0c;无法发送。有没有什么办法可以缩小文件的体积呢&#xff1f;今天给大家介绍几款可以用于视频…

Python中Python-docx 包的run介绍

先对run做一个简单地介绍。每个paragraph对象都包含一个run对象的列表。举例&#xff1a; 这是一个简短的段落。 from docx import Document doc Document("1.docx") #上面这段话保存在1.docx中 print("这一段的run个数是&#xff1a;",len(doc.paragr…

leetcode热题100.划分字母区间

Problem: 763. 划分字母区间 文章目录 题目思路复杂度Code 题目 给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段&#xff0c;同一字母最多出现在一个片段中。 注意&#xff0c;划分结果需要满足&#xff1a;将所有划分结果按顺序连接&#xff0c;得到的字符串仍…

基于Leaflet.js和Turf.js的等值线区间自定义及颜色自适应实践

目录 前言 一、Turf.js等值线相关制作 1、生成方法 2、主要参数 二、实际案例开发 1、新建展示页面 2、等值线生成 3、基于Leaflet的再优化 总结 前言 在气象方面的GIS应用当中&#xff0c;会根据实际的工作需要建立不同的监测站点。气象监测站的主要功能包括&#xff1…

如何快速识别陶瓷件的外观缺陷吗?

陶瓷件由陶瓷材料制成的物品或零部件&#xff0c;通常用于装饰、日常生活用品、工艺品或工业应用。陶瓷是一种非金属材料&#xff0c;具有耐高温、耐磨损、绝缘、化学稳定等特性&#xff0c;因此在许多领域得到广泛应用。 本案针对陶瓷件尺寸长25mm*宽11mm*高2mm的产品的外观检…

物联网实战--驱动篇之(五)TEA和AES加密算法

目录 一、前言 二、TEA算法 三、AES算法 四、加解密测试 五、安全性保障 一、前言 物联网的安全性是经常被提及的一个点&#xff0c;如果你的设备之间通讯没有加密的话&#xff0c;那么攻击者很容易就能获取并解析出报文的协议&#xff0c;从而根据攻击者的需要进行设备操…

运行gitHub中的vue项目,遇到三个报错解决方案

报错1&#xff1a;解决npm run serve启动报错npm ERR Missing script:"serve" 启动项目的时候用npm run serve发现报了以下的错误 npm ERR! Missing script: "serve" npm ERR! npm ERR! To see a list of scripts, run: npm ERR! npm runnpm ERR! A co…