热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用malloc测量CPU与Wall时间的奇怪差异

答:用户和内核cpu时间是分开测量的,小心!编辑:pTimes现在在每个基准测试之间重置为零,但结果变得更奇怪了!最终目标是摆弄我自己的自定义内存管理方案,我

答:用户和内核cpu时间是分开测量的,小心!

编辑:pTimes 现在在每个基准测试之间重置为零,但结果变得更奇怪了!

最终目标是摆弄我自己的自定义内存管理方案,我为 Visual Community 2019、Windows 10 中现有的 malloc() 做了一个简单的基准测试。出于兴趣,我对 CPU 时间和墙时间进行了基准测试,然后我通过在许多块中分配大块内存,然后单独释放每个块而不使用它们来测试 malloc。看这里:

void malloc_distr256(int nMemsize) {
long long pFreeList[256];
for (int i = 0; i <256; ++i) pFreeList[i] = malloc(nMemsize >> 8);
for (int i = 0; i <256; ++i) free((void*)pFreeList[i]);
}
void malloc_distr64(int nMemsize) {
long long pFreeList[64];
for (int i = 0; i <64; ++i) pFreeList[i] = malloc(nMemsize >> 6);
for (int i = 0; i <64; ++i) free((void*)pFreeList[i]);
}
void malloc_distr0(int nMemsize) {
void* pMem = malloc(nMemsize);
free(pMem);
}

我使用以下代码对这些函数进行了基准测试 - “BenchTimes”只是一个保持双 CPU/wall 时间的结构:

inline double cputime() {
FILETIME lpCreationTime;
FILETIME lpExitTime;
FILETIME lpKernelTime;
FILETIME lpUserTime;
if (GetProcessTimes(GetCurrentProcess(), &lpCreationTime, &lpExitTime, &lpKernelTime, &lpUserTime)) {
double dUnits = (double)(lpUserTime.dwLowDateTime | (long long)lpUserTime.dwHighDateTime <<32);
return dUnits * 0.1;
}
else return 0xFFF0000000000000;
}
inline double walltime() {
LARGE_INTEGER lnFreq, lnTime;
if (QueryPerformanceFrequency(&lnFreq)) if (QueryPerformanceCounter(&lnTime))
return 1000000.0 * (double)lnTime.QuadPart / (double)lnFreq.QuadPart;
//multiply by 1,000,000 to convert seconds to microseconds
//because the cpu time measurer I had in microseconds as well
return 0.0;
}
void bench(void (pfnFunc)(int), int nMemsize, int nIters, int nReps, BenchTimes* pTimes) {
pTimes->dCpuTime = 0.0;
pTimes->dWallTime = 0.0;
for (volatile int r = 0; r double dCpuStart = cputime();
double dWallStart = walltime();
for (volatile int i = 0; i double dCpuEnd = cputime();
double dWallEnd = walltime();
double dCpuDiff = dCpuEnd - dCpuStart;
double dWallDiff = dWallEnd - dWallStart;
pTimes->dCpuTime += dCpuDiff;
pTimes->dWallTime += dWallDiff;
}
}

这些是在我的电脑 (i5-9400f) 上测量的时间,以秒为单位。

我很好奇性能和 Wall time 与 CPU 时间比较中的巨大差异!

运行它的代码在这里:

BenchTimes sTimes;
bench(malloc_distr256, 1 <<20, 100, 1000, &sTimes);
fprintf(stdout, "Malloc alloc/free bench allocated %lf megabytes, distributed over 256 chunksn", (double)(1 <<20) / 1000000);
fprintf(stdout, "Malloc alloc/free bench returned:nWalltime - total: %lfnCPU Time - total: %lfn", sTimes.dWallTime / 1000000, sTimes.dCpuTime / 1000000); bench(malloc_distr64, 1 <<20, 100, 1000, &sTimes);
fprintf(stdout, "nMalloc alloc/free bench allocated %lf megabytes, distributed over 64 chunksn", (double)(1 <<20) / 1000000);
fprintf(stdout, "nMalloc alloc/free bench returned:nWalltime - total: %lfnCPU Time - total: %lfn", sTimes.dWallTime / 1000000, sTimes.dCpuTime / 1000000);
bench(malloc_distr0, 1 <<20, 100, 1000, &sTimes);
fprintf(stdout, "nMalloc alloc/free bench allocated %lf megabytes, distributed over no chunksn", (double)(1 <<20) / 1000000);
fprintf(stdout, "nMalloc alloc/free bench returned:nWalltime - total: %lfnCPU Time - total: %lfn", sTimes.dWallTime / 1000000, sTimes.dCpuTime / 1000000);
system("pause");

回答


malloc是通过HeapAlloc它在名为 的系统函数中实现的RtlAllocateHeap

该函数管理堆。它通过VirtualAlloc[Ex]或等效的方式分配系统内存页面,并在这些页面内提供较小的分配。

对于较大的分配,VirtualAlloc[Ex]每次分配都会调用等效项,对于较小的分配,它会偶尔调用。

VirtualAlloc[Ex]是使用NtAllocateVirtualMemory内核调用实现的。花在其中的大部分时间都不计入lpUserTime

另一方面,QueryPerformanceCounter是诚实的总时间。






推荐阅读
  • 线程漫谈——线程基础
    本系列意在记录Windwos线程的相关知识点,包括线程基础、线程调度、线程同步、TLS、线程池等。进程与线程理解线程是至关重要的,每个进程至少有一个线程,进程是线程的容器,线程才是真正的执行体,线程必 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • Redis底层数据结构之压缩列表的介绍及实现原理
    本文介绍了Redis底层数据结构之压缩列表的概念、实现原理以及使用场景。压缩列表是Redis为了节约内存而开发的一种顺序数据结构,由特殊编码的连续内存块组成。文章详细解释了压缩列表的构成和各个属性的含义,以及如何通过指针来计算表尾节点的地址。压缩列表适用于列表键和哈希键中只包含少量小整数值和短字符串的情况。通过使用压缩列表,可以有效减少内存占用,提升Redis的性能。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 本文介绍了在处理不规则数据时如何使用Python自动提取文本中的时间日期,包括使用dateutil.parser模块统一日期字符串格式和使用datefinder模块提取日期。同时,还介绍了一段使用正则表达式的代码,可以支持中文日期和一些特殊的时间识别,例如'2012年12月12日'、'3小时前'、'在2012/12/13哈哈'等。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
  • Visual C# TabControl中TabPage分离成若干个Form的小办法
    写Visual的同学们都会用到这个TabControl的控件,然后会分好几页的TabPage,每页都有很多控件和业务逻辑,但是每页的关系也 ... [详细]
  • 初识java关于JDK、JRE、JVM 了解一下 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • FIN7后门工具伪装成白帽工具进行传播
    fin7,后门,工具,伪装,成,白, ... [详细]
  • 完成字符串和时间对象的转化(DateFormat)、(以及日历Calendar用法)
    DateFormat 和SimpleDateFormat示例(时间格式的书写)packagecn.date;importjava.text.DateFormat;importjav ... [详细]
author-avatar
v05736708
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有