【C++数据结构】性能测量

news2024/12/1 0:20:03

性能测量

4.1 引言

容易计算内存的需求大小,只要知道编译后的代码和数据空间的大小就可以了;

数据空间的大小取决于用户所要解决的问题实例的大小。

要确定程序运行时间,需要通过实验来测量。

程序性能不仅依赖操作类型和数量,而且依赖数据和指令的内存模式。

性能测量(performance measurement)关注的是一个程序实际需要的空间和时间。

运行空间,我们无法明确地考量,这是因为如下两个因素:

  • 指令空间和静态分配的数据空间是由编译器在编译时确定的,它们的大小可以用操作系统指令来得到。

  • 递归栈空间和动态分配的变量空间可以用程序性能分析方法明确地估算。

运行时间,首先确定定时机制:

本书使用C++函数clock()来测量时间,它用“滴答”数来计时。在头文件time.h中定义了常数CLOCK_PER_SEC,它记录每秒流逝的“滴答”数,并转换成秒。CLOCK_PER_SEC=1000,滴答一次等于一毫秒。

也有更精确的时间函数,例如QueryPerformanceCounter。

4.2 选择实例的大小

确定实例特征n的值需要以下两个因素:程序执行的时间及执行的次数。

个人理解就是根据实际情况选择合适的实例大小

4.3 设计测试数据

为了使很多程序能够产生最好和最坏复杂度,我们可以徒手设计或借助计算机设计相应的测试数据。可是通常很难设计可以产生平均复杂度的测试数据。

如果不能为预期的复杂度设计一组测试数据,那就从随机生成的数据中选择用时最少(最多,平均)的数据作为测试数据,以得到最好(最坏,平均)复杂度的估算值。

4.4 实验设计

误差在10%以内的测量程序

PerformanceMeasurement.h

#pragma once
#ifndef __PERFORMANCEMEASUREMENT_H_
#define __PERFORMANCEMEASUREMENT_H_
template<class T>
void insertionsort(T a[], int n)
{
    //对数组a[0:n-1]实施插入排序
    for (int i = 1; i < n; i++)
    {
        //把a[i]插入a[0:i-1]
        T t = a[i];
        int j;
        for (j = i - 1; j >= 0 && t < a[j]; j--)
            a[j + 1] = a[j];
        a[j + 1] = t;
    }
}
void PerformanceMeasurement();
#endif

PerformanceMeasurement.cpp

#include "_0PerformanceMeasurement.h"
#include "time.h"
#include <iostream>
using namespace std;
​
void PerformanceMeasurement()
{
    int a[1000], step = 10;
    double clocksPerMillis = double(CLOCKS_PER_SEC)/ 1000;//每毫秒滴答一次
    cout << "The worst-case time,in milliseconds,are" << endl;
    cout << "n\tRepetitions\tTotal Ticks\tTime per Sort" << endl;
    //次数n = 0,10,20,.,100,200,300,…,1000
    for (int n = 10; n <= 1000; n += step)
    {
        //为实例特征n测量运行时间
        long numberofRepetitions = 0;
        clock_t startTime = clock();
        do
        {
            numberofRepetitions++;
            //用最坏测试数据初始化
            for (int i = 0; i < n; i++)
                a[i] = n - i;
            insertionsort<int>(a,n);
        }
        while (clock() - startTime < 1000);
        //重复运行,直到有足够的时间流逝
        double elapsedMillis = (clock() - startTime) / clocksPerMillis;
        cout << n << '\t'<< numberofRepetitions <<'\t'<<'\t'<< elapsedMillis <<'\t'<<'\t'<< elapsedMillis/numberofRepetitions << endl;
        
        if(n == 100) 
            step = 100;
    }
}

main.cpp

/*
Project name :          allAlgorithmsTest
Last modified Date:     2022年8月13日17点38分
Last Version:           V1.0
Descriptions:           main()函数,控制运行所有的测试函数
*/
#include <iostream>
#include "_0PerformanceMeasurement.h"
​
int main()
{
    PerformanceMeasurement();
    return 0;
}

4.5 高速缓存

4.5.1 简单计算机模型

简单的计算机模型:它的存储由一个一级缓存L1(level 1)、一个二级缓存L2和主存构成。算术和逻辑操作由算术和逻辑单元(ALU)对存储在寄存器(R)中的数据进行处理来完成。图4-5是这个计算机模型的一部分。

通常,主存的大小是几十或几百MB;二级缓存的大小不足1MB;一级缓存的大小是几十KB;寄存器的数量在8和32之间。程序开始运行时,所有数据都在主存。

要执行一个算术运算,例如加法,首先把相加的数据从主存移到寄存器,然后把寄存器的数据相加,最后把结果写人主存。

我们把寄存器的数据相加所需要的时间作为一个周期。把一级缓存的数据送到一个寄存器所需要的时间是两个周期。如果需要的数据没有在一级缓存,而是在二级缓存,即一级缓存未命中,那么把需要的数据从二级缓存送到一级缓存和寄存器需要10个周期。当需要的数据没有在二级缓存,即二级缓存未命中时,把需要的数据从主存复制到二级缓存、一级缓存和寄存器需要100个周期。我们把写操作,甚至向主存的写操作,算作一个周期,因为不需要等到写操作完成之后再进行下一个操作。

4.5.2 缓存未命中对运行时间的影响

就是会增加程序的运行时间。

减少缓存未命中的数量:目的是减少程序的运行时间,把最近需要处理的数据预载到缓存中,当出现一个缓存未命中时,把需要的数据和相邻字节中的数据装入缓存中。当连续的计算机操作使用的是相邻字节的数据时,这个策略很有效。

4.5.3 缓存未命中举例-矩阵乘法

把程序4-4的三层嵌套for循环重新排列一下顺序,结果是不变的。我们把程序4-4的嵌套循环顺序称为ijk。当我们把第二层和第三层的for循环交换次序,我们得到的嵌套循环顺序是ikj。一共有3!=6种嵌套循环顺序。由6种嵌套循环顺序分别生成的函数都以同样的数量执行每一种类型的操作。因此你也许认为这些函数所需的运行时间也是相同的。但是错了。改变了循环的次序,也就改变了数据访问模式,进而改变了缓冲未命中的数量,最终影响了运行时间。

在ijk顺序中,数组a和c的元素是按行访问的,数组b的元素是按列访问的。因为同行的元素在存储中是相邻的,而同列的元素在存储中是分开的,所以当数组很大,以至三个数组不能同时存储在二级缓存L2中的时候,访问数组b可能导致很多二级缓存未命中的事件。 在ikj的顺序中,数组a、b和c的元素是按行访问的,因此二级缓存未命中的事件就比较少,因此所需时间也比较少。

 

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

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

相关文章

Excel逆向查询的多种方法,赶快学起来

关于匹配查询&#xff0c;我们平时用的做多的就是VLOOKUP函数了&#xff0c;但VLOOKUP函数只能正向查找&#xff0c;不能逆向查询。 像是下面这种情况就不可以&#xff1a; &#xff08;现在我们想用编码去匹配书名&#xff09; 如果在不改变原表格结构的基础上查找出书目编码…

当MySQL和java通过媒婆navicate谈上了恋爱 ------ MySQL的安装和Java的连接

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 **收录于专栏 数据库 ⭐当MySQL和java通过媒婆navicate谈上了恋爱⭐ 文章目录⭐当MySQL和java通过媒婆navicate谈上了恋爱…

vue组件库发布到npm

修改项目的信息 在package.json文件中&#xff1a; 修改Readme文件的信息 注册npm 账号 指路官网 vscode终端登录npm 执行 npm login 输入用户名&#xff0c;密码&#xff0c;邮箱&#xff0c;邮箱验证码 如下图 执行 npm publish 如下图 出现的问题 npm ERR! code E403 …

CSAPP Lab6:Malloc

文章目录一、实验简介二、隐式链表实现基本宏块的相关函数mm_initmm_mallocmm_freemm_reallocextend_heapblk_mergeblk_findblk_split使用下次匹配三、显式链表实现四、分离适配五、完整代码隐式链表显式链表课本实现一、实验简介 实现一个动态内存分配器。 tar xvf mallocla…

Linux 应急响应命令总结,收藏版

系统排查 系统基本信息 CPU 信息 CPU 信息&#xff1a;lscpu 操作系统信息 操作系统信息&#xff1a;uname -a 操作系统信息&#xff1a;cat /proc/version 模块信息 模块信息&#xff1a;lsmod 账户信息 系统所有账户 系统所有账户&#xff1a;cat /etc/passwd 超级权限账户 超…

3D-SKIPDENSESEG医学图像分割

蓝色三角、黄色三角、红色三角相对应。 得到第三个feature map&#xff0c;反卷积会恢复到原来的尺寸 Dense block&#xff0c;通道增加了 Transition&#xff0c;池化 用正则表达式把里面的h5文件匹配一下吧 os.path.join()把两个部分的路径拼一下 root_path —data_train *.…

[kubernetes]-k8s开启swap

导语&#xff1a;记录k8s开启swap后先后做的调整 测试版本 k8s1.20版本 使用参数--fail-swap-onfalse Environment"KUBELET_EXTRA_ARGS--fail-swap-onfalse"使用测试 可以开启swap不报错 但是pod使用swap不太理想。且无法实现在使用swap的时候限制pod的内存。会造…

【Java面试】List接口

文章目录Iterator 和 ListIterator 有什么区别&#xff1f;遍历一个 List 有哪些不同的方式&#xff1f;每种方法的实现原理是什么&#xff1f;Java中List 遍历的最佳实践是什么&#xff1f;说一下 ArrayList 的优缺点如何实现数组和 List 之间的转换&#xff1f;ArrayList 和 …

M4 tm4c1294单片机软件调式总结

1&#xff0c;框架图&#xff1a; 调式基本方法&#xff1a; &#xff08;1&#xff09;加串口打印初始化&#xff0c;单步跟踪查看&#xff0c;类似gdb的单步&#xff1b; &#xff08;2&#xff09;打印命令行&#xff0c;重点参数添加命令行打印; &#xff08;3&#xff…

Redis 的相关基础知识

【一】 Redis 中默认的端口号为什么是6379 图中的人名为 Alessia Merz &#xff0c;其中的 Merz 对应的九键输入法按出来的就是6379 【二】 Redis 默认的数据库 Redis 中默认使用的是16个数据库&#xff0c;类似数组下标从0开始&#xff0c;初始默认使用0号数据库 【三】 Redis…

vscode搭建Verilog HDL开发环境

工欲善其事&#xff0c;必先利其器。应该没有多少人会使用Quartus和vivado这些软件自带的编辑器吧&#xff0c;原因在于这些编辑器效率很低&#xff0c;Verilog HDL代码格式比较固定&#xff0c;通常可以利用代码片段补全加快书写。基本上代码写完之后才会打开Quartus或者vivad…

一文带你了解Spring中的事务管理

文章目录前言一、事务的基础概念二、spring中事务的使用声明式事务编程式事务如何选择事务方式三、spring中事务管理实现原理前言 本文将涉及以下知识点&#xff1a; 事务的基础概念spring当中事务的使用spring当中事务管理的实现原理 一、事务的基础概念 事务&#xff08;T…

python画图

python画图1.使用matplotlib画图2.使用pyecharts画图2.x pyecharts的三种图片渲染工具2.x.1 snapshot_selenium2.x.2 snapshot_phantomjs2.x.3 snapshot_pyppeteer1.使用matplotlib画图 2.使用pyecharts画图 pyecharts是一款将python与echarts结合的强大的数据可视化工具&…

阿里云服务器安装tomcat

一、前置条件 安装tomcat需要先安装jdk&#xff0c;所以没有安装jdk同学&#xff0c;详见参考文章或者此文章 二、Linux上安装tomcat 1. 下载Apache tomcat tomcat官网下载地址 在左边&#xff0c;可以选择下载各种版本的tomcat。根据服务器操作系统选择下载。Linux操作系统…

第七章TCP/IP——ARP网络攻击与欺骗

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。个人爱好: 编程&#xff0c;打篮球&#xff0c;计算机知识个人名言&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石…

分布式文件系统和对象存储魔力象限,右上角都有谁?

自Gartner 首次发布      分布式文件系统和      对象存储魔力象限以来      戴尔科技集团      就牢牢位居领导者象限      今年也不例外      恭喜      连续第七年获评领导者!    对于入选本年度的魔力象限领导者,我们感到十分荣幸。我们相…

docker安装jenkins最新版

前言 使用的是centos7的linux系统&#xff0c; 检查docker 是否开启网络 如果没有开启网络会报错:WARNING: IPv4 forwarding is disabled. Networking will not work. 检查网络状态 sysctl net.ipv4.ip_forward如果返回为“net.ipv4.ip_forward 1”则表示网络转发正常&am…

1534_TriCore编译器Tasking使用_汇编语言语法以及标识符

全部学习汇总&#xff1a; GreyZhang/TriCore_Tasking_Compiler_Skills: Some skills for Tasking compiler on AURIX platform. Happy hacking! (github.com) 1. 如同C语言&#xff0c;汇编语言也可以续行而且采用了同样的续行符号。不过&#xff0c;我遇到的汇编一直都是很统…

TMS Echo数据复制的Delphi框架

TMS Echo数据复制的Delphi框架 TMS Echo是用于数据复制的Delphi框架。它是TMS Business产品阵容的一部分&#xff0c;它取决于TMS Aurelius的运营。 TMS Echo允许您至少拥有两个数据库并在它们之间同步信息。您对单个客户数据库所做的更改(插入、更新、删除)可能会传输到其他数…

PowerMax——业界首个引入NVIDIA BlueField DPU的高端存储

高性能、可扩展、弹性与空间 全球越来越多的领先企业 都依靠关键任务型存储 承载企业核心业务 DPU作为一个新兴起的概念,正在以惊人的速度崛起。据预测,DPU将成为未来计算的三大支柱之一,CPUGPUDPU构成未来的数据中心。 现在,全球首款 集成NVIDIA BlueField DPU技术的 关…