网站后台上传案例能同步到博客吗,网络营销推广实例,水果电商网站建设相关文献,asp.net个人网站怎么做仓库:https://gitee.com/mrxiao_com/2d_game_2
黑板#xff1a;优化的基本过程
在游戏编程中#xff0c;优化是一个非常重要的学习内容#xff0c;尤其是想要成为专业开发者时。优化的核心是理解代码的执行速度#xff0c;以及如何提升其性能。在这个阶段#xff0c;已经…仓库:https://gitee.com/mrxiao_com/2d_game_2
黑板优化的基本过程
在游戏编程中优化是一个非常重要的学习内容尤其是想要成为专业开发者时。优化的核心是理解代码的执行速度以及如何提升其性能。在这个阶段已经开始讨论如何有效地进行优化。
首先需要收集统计数据这是优化的第一步。收集数据的目的是为了了解程序运行缓慢的地方找出具体的瓶颈并分析这些部分的特点比如它们处理了多少内容、执行的频率如何等。这些信息将帮助确定哪些代码部分需要被优化。
接下来基于收集到的统计数据进行估算。估算的目的是根据现有数据推测出代码应该达到的理想性能。尽管很难做到准确但可以通过估算得到一个大致的参考值了解当前性能与理想性能之间的差距。
然后进行效率和性能分析。效率和性能是两个不同的概念效率指的是代码实际做了多少工作而性能则是指完成这些工作的速度。提高效率意味着减少实际需要做的工作量而提高性能则是让这些工作通过CPU更快速地完成。
一旦分析了效率和性能的差异就可以判断出优化的潜力。最后根据分析结果开始编写优化代码并测试其效果看是否能够提升性能。
总结来说优化过程包含四个步骤收集数据、进行估算、分析效率和性能、以及编写优化代码。通过这一过程可以系统地改进代码的执行效率和速度。
收集统计数据
首先要进行的是收集统计数据这主要涉及编程的部分。我们需要开始收集一些统计信息。收集统计数据的方式是对代码进行“图表化”即在代码中添加一些内容使其能够报告统计数据给我们。虽然有一些商业程序可以分析代码如 Intel 的 vtune 等但这里不打算使用这些工具而是展示如何自己编写并收集统计数据。如果进行深入优化可能会选择使用一些工具像 Intel 提供的工具或者其他地方的工具它们能提供一些程序运行的内部信息这些是我们通过简单的仪表化可能无法得到的。
我们将专注于实现一个简单的统计收集方法。首先需要知道的是在 CPP 中游戏的更新和渲染是我们负责的代码部分即不在 Windows 系统内。我们想要了解的是游戏更新和渲染调用总共消耗了多少处理器周期。然后我们还希望能看到在其中一些代码片段的执行过程中分别消耗了多少处理器周期这样可以帮助我们大致了解哪些部分的代码可能会影响程序的运行速度。
虽然我们已经知道渲染器目前非常慢因为在进行相关更改时已经观察到它的性能下降所以此时并不一定需要重新分析渲染器部分的代码。但为了能够跟踪那些性能可能不那么直观的部分还是决定进行一些通用的仪表化工作。这么做是为了展示如何找出性能瓶颈。实际上如果只想尽可能快速地完成这个过程我们可以直接获取游戏代码的总处理器周期数再获取绘制矩形慢操作的处理器周期数然后对比两者直接看出慢的部分。但现在决定采用稍微复杂一点的方法来实现这个目标。
重新审视 __rdtsc
目标是创建一个简单的系统能够记录处理器周期并计算两个位置之间所花费的周期数。实际上这种功能我们已经实现过一次早在处理 Win32 平台层时就已经有过类似的代码这段代码被称为 DTSC。
DTSC 使用了一个处理器指令称为 read time stamp counter这是编译器通过内嵌指令生成的汇编指令。这个指令的作用是提供一个来自处理器的计数器表示当前处理器在指令流中的位置换句话说它表示处理器执行了多少个周期。需要注意的是“周期”这个词现在有些模糊因为不同的处理器可能以不同的方式报告周期时间特别是在启用了“SpeedStep”等技术的处理器上。
不过现代处理器通常会给出在满速运行下的周期数即使在启用节能模式如笔记本的处理器会在不同负载下调整功耗时可能也能给出一个相对准确的周期计数。如果处理器频率时常变化可能需要更小心地处理这些周期数据但如果处理器在高性能模式下运行假设 DTSC 提供的周期数与实际周期数接近可以大致认为数据是准确的。
GAME_UPDATE_AND_RENDER添加 __rdtsc 循环计数
可以像之前那样通过记录开始和结束时的 __rdtsc 来计算经过的周期数。具体做法是在函数的开始和结束处获取时间戳计数器的值然后通过计算这两个值的差异来得出执行该代码段所花费的周期数。
简单来说首先在代码段开始处记录一个起始周期计数使用 __rdtsc 获取初始计数值然后在代码段结束时记录一个结束周期计数同样使用 __rdtsc。计算这两个值的差异即可得到该代码段执行所消耗的处理器周期数。
基本的实现方式是在代码开始时获取开始周期数在结束时获取结束周期数然后计算它们的差值。这样就能够得到该段代码执行所用的总周期数。
然而在这个过程中存在一个问题。
在 game_platform.h 中引入 debug_cycle_counter
目前我们没有办法将任何信息输出到屏幕上。虽然 Win32 代码能够输出内容但游戏本身并没有输出的能力因为游戏并没有显示功能甚至没有相关的输入输出支持。因此想要将统计数据输出到 Win32 层需要简单地通过一些基本的方式实现。
为了实现这一点可以做一些简单的操作。考虑到许多性能计数器的实现有时过于复杂这里决定采取一个非常简单的办法创建一个静态表来存储这些计数器。实现过程非常直接基本上只是创建一个简单的结构来存储周期计数。
在游戏的内存管理部分新增一个名为 debug cycle counter 的计数器。这个计数器会是一个 uint64_t 类型用来记录周期数。在调试模式下会有多个这样的计数器。举个例子可以在游戏调试内存区域分配 256 个这样的计数器。
这些计数器只是用来调试时使用的在发布版本时可以去掉。为了避免在发布版本中仍然保留这些调试信息可以将它们放到一个名为 game_internal 的区域只有在调试模式下定义 game_internal 时才会启用这些计数器。这样就能在开发和发布版本之间灵活切换确保发布版本没有多余的调试信息。
支持 Linux 和 Mac 等平台的用户
为了避免对其他平台的支持产生问题特别是处理器不支持 __rdtsc 指令的情况可以通过宏来实现这一功能。首先确定编译器是否支持 __rdtsc然后在符合条件的情况下使用宏来处理代码的开始和结束时间记录。
具体做法是创建一个宏名为 BEGIN_TIMED_BLOCK它接受一个 ID用于标识该时间块。宏的作用是记录代码块执行的开始时间然后通过 __rdtsc 获取当前的周期数。同样的创建另一个宏 END_TIMED_BLOCK它在代码块结束时再次调用 __rdtsc 获取结束时间然后计算两次周期数的差值这个差值即为代码执行的周期数。
为了避免在同一作用域中多个时间块可能造成的命名冲突使用了 C 的拼接操作符将 ID 添加到计数器名称中。这样可以确保每个计时器都有唯一的名称即使多个计时器位于同一函数内。
计时器的计数值会存储在一个本地变量中而实际的周期数则会存储在相应的调试内存中。为了方便扩展可以通过枚举类型定义不同的计数器如 DebugCycleCounter_Count 等。这样可以使代码更简洁同时也能避免硬编码。
最终计时器的使用方式变得非常简单只需要在代码块开始和结束时调用 BEGIN_TIMED_BLOCK(ID) 和 END_TIMED_BLOCK(ID)并指定对应的 ID即可自动记录并计算执行该块代码所消耗的处理器周期数。
编译、清理并运行
在进行编译之前需要先解决一些错误。首先调整类型定义然后确保 time block 的值能够正确累加到 CycleCount 中。还需要解引用该值以确保其正确更新。
修改完成后理论上如果运行游戏每次游戏代码迭代时周期计数器的值会逐步增加。接下来考虑将代码切换到发布模式进行编译了解为什么要这样做以便在最终版本中进行优化和性能验证。
FillGroundChunk关闭地面块
为了减少构建地面块时的运行时间压力暂时关闭了填充地面块的功能。在这一过程中地面块仍然在生成但它们被填充为黄色而不是实际内容。这么做可以确保在调试计时器功能时地面块的构建不会对测试结果产生影响。等到计时器部分正常工作后再重新启用地面块的填充功能。
查看计时器值
为了查看计时器的值需要先确保在调用 game update and render 时调试计数器中的所有计时器都被清零。可以使用一个类似 Windows Zero Memory 的方法来清除这些计时器。接着创建一个新的函数来转储计时器信息以便在每次更新和渲染后输出这些计时器的值。
在 handleDebugCycleCounters 函数中首先要确保只有在启用了内部调试时才执行相关代码避免在没有调试计数器时出现编译错误。然后通过一个循环遍历每个计数器并使用 OutputDebugString 函数将每个计数器的值输出。此输出将包括计数器的索引及其相应的周期计数值。为了正确输出 64 位整数需要使用合适的格式符号。最终这些输出将帮助追踪每个计时器的状态并调试游戏性能。
这一过程为调试提供了基础输出但将来可能会通过自定义调试服务进行更精细的处理。目前这种方法虽然简单但足以满足当前的需求。 运行游戏并查看调试循环计数
调试输出现在可以显示每帧游戏运行所消耗的周期数。从输出中可以看到当前每帧的周期数相对一致但却非常高。具体来说当前游戏代码本身就已经消耗了debug大约 31 亿个周期release 1.2亿个周期 而不包括 Windows 操作系统的开销。根据之前的计算每个 CPU 核心每帧应当消耗的周期数应该低于 1.07 亿而现在的数字远远超出了这个预期。这表明当前代码的性能开销较大需要进一步优化。 debug模式 0: 3,289,537,500 三十多亿个周期吗
release模式 0: 119925458
确认我们知道的情况
从周期计数来看可以确认目前的帧率远低于期望值游戏的性能无法达到理想的水平。周期计数显示的数字远远超过了实际发布时所能接受的范围这证明了当前的代码效率不高无法支持足够的帧率。因此接下来的步骤是分析并改进代码优化性能以提高帧率。
RenderGroupToOutput添加一个定时块
为了更清楚地了解每个部分消耗的周期可以通过在渲染和模拟等关键操作中添加计时器来跟踪时间。例如渲染的处理是通过 RenderGroupToOutput 函数完成的可以在该函数内部插入一个时间块标记为 DebugCycleCounter_RenderGroupToOutput。通过这种方式能够记录并显示渲染过程中花费的周期从而进一步分析各个部分的性能瓶颈。
引入 DebugGlobalMemory 以便在不应访问的情况下仍然能够访问这些计时信息
接下来为了避免频繁传递调试周期计数器可以使用一个全局变量来存储调试内存从而让所有地方都能访问到它。这样虽然通常会避免使用全局变量但在这种性能分析的情况下它有助于简化调试流程。这个全局变量 DebugGlobalMemory 会在内部模式下定义并且只有在内部模式下编译时才会有效从而避免在发布版本中误用。
此外确保这些调试宏在其他平台上完全被编译掉不会影响正常运行。通过在游戏更新和渲染过程中设置这个全局变量可以保证每次访问时都能获得调试数据而无需改变程序的架构。 注意两个循环计数之间的差异
通过查看调试周期计数器的输出可以清楚地看到游戏的整体性能情况。通过对比不同部分的周期数可以得出以下结论整个游戏的运行只消耗了大约 267286次周期而渲染部分则消耗了剩余的大部分周期约111686539多次。这一数据确认了之前的观察结果即游戏本身的计算工作量较少而渲染过程则是性能瓶颈的主要来源。
尽管这还不是非常精确的分析但已经能大致勾画出性能瓶颈的位置验证了游戏中明显的性能下降正是由于渲染部分的高周期消耗所导致的。接下来计划继续深入分析并优化这一部分。
0: 111953825 - 1: 111686539 267286
确认 DrawRectangleSlowly 是罪魁祸首
为了进一步确认性能瓶颈所在决定对 DrawRectangleSlowly 这一函数进行检查。虽然最初的假设是渲染部分可能导致性能问题但在没有确认之前不能仅凭直觉做出优化因为这可能会浪费时间在非关键部分。实际运行时结果证明了这一假设几乎所有的时间都花费在了 DrawRectangleSlowly 函数上。
通过对比不同函数的周期消耗发现大部分时间的消耗确实集中在渲染部分尤其是在绘制小三角形的过程中。这也证明了渲染环节仍然是性能瓶颈的核心。虽然渲染过程中可能还有一些其他小的耗时操作但问题的主要根源已经明确为后续的优化提供了方向。 引入 HitCount 以了解 DrawRectangleSlowly 是因为本身慢还是因为调用次数太多
为了进一步确认 rawRectangleSlowly 是否真的因为本身效率低导致性能问题还是因为其调用频率过高决定在现有的周期计数系统中加入执行次数的统计。通过为每个函数路径增加一个“命中计数”可以追踪每个代码块被执行的次数。
这样除了更新周期计数DTSC还可以增加对命中计数的更新记录函数被调用的次数。为了展示这些数据扩展了输出除了显示周期计数外还增加了每个函数调用的命中次数、周期数和每次调用的平均周期数周期数除以命中次数。这有助于确认是否是函数调用过于频繁导致了性能瓶颈。对于命中计数为零的情况避免除以零的错误只在有命中次数时进行输出确保输出的数据有效。 发现我们调用渲染器 13 次DrawRectangleSlowly 被调用了 202 次
通过加入命中计数发现了一个之前未曾注意到的现象渲染器被调用了13次原因可能是因为正在刷新地面块。原本认为渲染器只会调用一次但实际情况并非如此。另外rawRectangleSlowly 被调用了202次。通过这些数据可以看出问题并不是矩形绘制过多而是这些矩形本身足够大且绘制速度较慢导致每个矩形的绘制消耗了大量时间。
这些结果确认了之前的假设但更重要的是这个过程展示了如何通过层级化的调试方法来确认性能瓶颈所在。在不知道时间消耗具体位置的情况下这种方法非常有效能够帮助快速定位性能问题。
计算我们正在填充的像素数
为了进一步分析性能决定临时添加一个计数器来统计在渲染过程中实际填充了多少像素。通过在rawRectangleSlowly函数中添加FillPixel和TestPixel计数器可以跟踪每次循环中测试和填充的像素数量。从结果来看大部分测试的像素确实被填充了表明并没有浪费太多时间在无效的像素上这是一个积极的信号。
然而值得注意的是虽然FillPixel和TestPixel的数量相似但这也暴露出一个潜在的问题如果没有进行旋转理论上应该能精确计算出需要填充的像素。因此若两者没有完全一致可能表明边界计算或边缘函数的实现存在问题这是一个明显的警示信号需要重新检查边界计算或修正边缘函数。 解读数据
正在讨论填充的像素数量。首先需要确认实际填充了多少像素因此检查了这个数字。然后查看了一个名为“scratch buffer”的内容这显示了已经测试过的像素数量。接着考虑到当前分辨率想知道屏幕上实际上有多少像素。分辨率为1204 x 800计算结果为963200。这一过程被重复进行了确认。
TestFill - 1531114h total - 963200
注意我们操作的像素数并没有比屏幕上的总像素数多多少
通过比较当前填充的像素数量与屏幕上总像素数可以看出实际上填充的像素并没有超过总像素的太多这意味着在过度绘制overdraw方面的表现还算不错。过度绘制是指在渲染过程中同一个像素被多次填充的情况当前的情况表明并没有出现过多的无效绘制。
黑板过度绘制
过度绘制overdraw是指在渲染过程中像素被多次触及的情况。理想的渲染器应该只触及每个像素一次并且准确地给每个像素上色。理想情况下渲染器的操作数应该等于屏幕上总像素的数量这意味着每个像素仅被绘制一次。过度绘制衡量的是渲染器的效率表示渲染器在渲染过程中需要重新绘制的像素次数。过度绘制的增加意味着渲染效率低下因为每次覆盖之前的像素都浪费了工作。因此过度绘制与渲染效率密切相关。
目前的测试结果显示测试像素的数量与屏幕上的像素数量差距不大这表明过度绘制的情况并不严重渲染效率还算不错。然而当前屏幕上没有太多内容因此随着内容的增加过度绘制的数量可能会上升需要通过创建一些测试场景来故意增加过度绘制以便进一步优化这一指标。
黑板进度报告
经过这些步骤现在已经了解了一些关键的性能特点。首先已经确定了性能瓶颈的具体位置并且了解了一些关于该瓶颈的特征。目前并没有出现显著的过度绘制问题渲染效率还可以。然而存在较大的速度问题。从周期数来看每个像素的处理时间约为160个周期。通过将像素数量与所消耗的周期数相除可以得出每个像素大约需要160个周期的处理时间。
关闭 NormalMap
目前每个像素的处理时间大约是160个周期这为进一步评估性能提供了一些信息。接下来通过不进行法线贴图合成的实验可以进一步了解渲染速度的变化。在没有法线贴图的情况下渲染速度的差距相对较小处理周期也有所减少。这表明法线贴图合成对当前性能的影响不小。
理解大致的时间估算
目前的周期计数只是一个大概的估算不能准确反映执行时间。即使游戏状态没有变化渲染的内容也相同周期数依然会波动。这是因为现代处理器复杂存在内存访问延迟、缓存命中、任务切换等因素这些都会引入不确定性导致每次周期计数不同。为了获得更准确的周期计数可以通过多次运行同一个操作取最低周期数来减少这些变动这样可以排除外部干扰并尽量将操作保持在缓存中从而更精确地测量最优周期数。然而目前所看到的周期计数只能作为粗略的参考不能视为绝对准确的数值。在查看分析结果时必须理解这些数字的含义以及它们的准确性。
进行估算
为了估算每个像素所需的操作首先需要分析渲染过程中的各种操作步骤。需要进行的操作包括变量重命名、减法、点积运算、取反、比较、屏幕空间坐标计算、乘法和采样等。一些步骤如旋转、颜色空间转换和分解可能需要额外的乘法、加法、减法和位移操作特别是在进行采样时。对于内存查找部分涉及的操作会更复杂因此需要考虑到的指令总数大致为96条。
通过粗略估算如果每个指令需要2个周期那么每个像素可能需要200个周期。若能够优化处理使得每个周期可并行处理四个像素那么每个像素的周期数将降到50个周期。假设通过优化将操作降到这种程度填充当前屏幕的像素可能需要4200万个周期。基于当前的测试像素数如果能够减少到100个周期以下则可能达到预期的性能目标。
最终优化的目标是尽量将每个像素的周期数降低到100周期以内同时考虑到法线映射等额外开销。这一过程需要在未来进一步细化和验证以确保渲染效率符合需求。 AVX-512 热议
如果使用像AVX2或即将推出的AVX-512处理器就可以显著提高效率。相比每次处理4个像素新的处理器能够每次处理16个像素这将大大提高渲染速度带来显著的性能提升。因此考虑到这种硬件进展可能会在未来优化渲染性能时发挥巨大作用。
为什么计数器上没有文本标签
在计数器上没有文本标签的原因是目前并不需要它们。虽然可以考虑以后加上但目前并不觉得有必要。
对不起如果这是你之前讲过的内容但能否解释一下 C 中 new 和 malloc() 之间的区别以及何时使用它们
new 和 malloc 之间的区别在于是否需要使用 C 的特性。malloc 仅分配内存而 new 不仅分配内存还会调用对象的构造函数。因此使用带有构造函数的对象时必须使用 new除非打算手动调用构造函数。对于没有构造函数的对象new 并不会做任何额外的事情malloc 就足够了。类似地对于带有析构函数的对象需要使用 delete 来释放内存而对于没有析构函数的对象可以直接使用 free 来释放内存。
你是否可以通过做更多的工作来省略一些指令例如 d - XAxis接着 d - XAxis - YAxis。那应该只需要 2 条指令吗
通过对之前的计算结果进行复用来减少指令的数量是完全可行的。例如可以通过先计算 D - XAxis然后再计算 d - XAxis - YAxis 来节省一些计算。虽然编译器已经开启优化可能会自动去除一些冗余的操作但依然会尽量手动进行优化避免多余的计算。
你认为我们会在软件渲染器中使用多线程吗
在软件渲染中确实会考虑使用多线程。计划将屏幕分成四个部分并在不同的线程中分别渲染每一部分。这种方式能够提高渲染效率并利用多核处理器的优势。
是否可以每次操作都做四倍优化
处理器如何发布指令以及如何管理不同指令的执行。处理器的工作方式是它只能在有足够空闲单元的情况下发布指令。可以将处理器看作由多个较小的单元组成每个单元负责不同的任务例如加法或位移操作。如果两个指令是独立的可以在同一周期内分别发给不同的单元执行。如果两个指令相同且依赖于相同的资源如同为位移指令则无法在同一周期执行。
优化指令发布的过程涉及深入了解处理器的结构例如每个单元的数量和处理器是否能够在一个周期内同时执行多个指令。这个过程是复杂的需要了解处理器的每个细节并考虑它的乱序执行窗口。对于x64处理器来说由于其复杂性和多样性这类优化特别困难。尽管如此在某些情况下确实有必要深入了解处理器以实现最大化的性能优化。
我的意思是把它放入宽指令SIMD中
关于是否可以在指令中进行四倍quad pump操作的问题回答是否定的。虽然浮点和整数运算通常可以进行四倍泵但内存访问操作例如纹理获取和计算需要加载的纹素位置是无法进行的。这是因为SSE2、AVX及其之前的指令集在内存访问方面有局限无法处理宽操作wide operations。虽然AVX-512可能解决了这个问题因为Larrabee指令集就包含了这些功能并且AVX-512已经将这些功能整合到主流指令集中了但在目前的指令集下内存访问仍然是一个瓶颈。
“Quad pump” 这个术语通常指的是在一个时钟周期内并行执行四个操作或指令的能力。它是在处理器架构中特别是与SIMD单指令多数据指令集相关的一个术语比如AVX高级向量扩展系列。
具体来说“quad pump” 的意思是在一次时钟周期内通过使用宽度较大的指令集例如 AVX-512能够并行处理更多的数据通常是每个时钟周期处理四倍于常规操作的数据量。
例如在一个支持 AVX 的处理器上如果能够处理四个浮点数或者四个整数数据项就可以称其为“quad pumping”。这使得处理器在执行某些任务时能够更高效地同时处理多个数据项显著提高性能尤其在图形处理、科学计算等需要大量并行运算的领域。
linux 下面perf
在Linux中执行CPU profiling通常可以使用多种工具以下是几种常见的方法
performance_test.cpp
#include iostream
#include vector
#include cmath
#include chrono// 模拟一个计算密集型函数
void compute_heavy_task(int size) {std::vectordouble vec(size, 0.0);for (int i 0; i size; i) {for (int j 0; j size; j) {vec[i] sqrt(i * j);}}
}int main() {int size 1000; // 调整为较大的数值增加计算密集性// 记录开始时间auto start std::chrono::high_resolution_clock::now();// 执行计算密集型任务compute_heavy_task(size);// 记录结束时间并计算花费的时间auto end std::chrono::high_resolution_clock::now();std::chrono::durationdouble duration end - start;std::cout Task completed in duration.count() seconds. std::endl;return 0;
}1. 使用 perf 工具
perf 是一个强大的性能分析工具可以用于收集CPU性能数据检查程序瓶颈。
安装 perf如果尚未安装
sudo apt-get install linux-tools-common linux-tools-generic基本使用
首先编译程序并启用调试信息
g -g -o performance_test performance_test.cpp然后使用 perf 来记录程序性能
perf record ./performance_test程序运行完后会生成一个 perf.data 文件。可以使用以下命令查看性能报告
perf report采样特定的事件 你可以通过 perf 来捕获特定的事件比如 CPU cycles 或缓存命中等
perf record -e cycles -p pid这会捕获指定进程PID的 CPU 周期事件。
rm 删掉除.cpp 的其他文件
要删除当前目录下除了 .cpp 文件之外的其他文件可以使用 find 命令结合 rm 来实现。以下是一个示例
find . -type f ! -name *.cpp -exec rm -f {} \;解释
find .从当前目录开始查找。-type f只查找文件。! -name *.cpp排除 .cpp 文件只删除不以 .cpp 结尾的文件。-exec rm -f {} \;对找到的每个文件执行 rm -f 命令删除文件。
注意
确保你在正确的目录中执行命令避免删除了不该删除的文件。如果不确定可以先使用 find 命令列出将被删除的文件例如find . -type f ! -name *.cpp这将列出所有不以 .cpp 结尾的文件你可以确认后再执行删除操作。
2. 使用 gprof 工具
gprof 是一个较为传统的性能分析工具可以帮助分析程序的执行性能。
使用步骤 编译程序 时确保加上 -pg 选项来启用性能分析 g -pg -o performance_test performance_test.cpp执行程序生成性能数据 ./performance_test生成 gmon.out 文件后使用 gprof 查看性能报告 gprof ./performance_test gmon.out analysis.txt3. 使用 valgrindcallgrind 模式
valgrind 是一个用于内存调试的工具但其 callgrind 模式可以用于进行性能分析尤其适用于 CPU 性能分析。
安装 valgrind
sudo apt-get install valgrind使用 callgrind
valgrind --toolcallgrind ./performance_test这会生成一个包含函数调用次数、调用图等信息的文件可以使用 kcachegrind 或 qcachegrind 来可视化分析。
修改WSL 界面的字体大小
1. 安装字体
sudo apt update
sudo apt install fontconfig2. 安装 x11-xserver-utils 包
xrdb 工具通常包含在 x11-xserver-utils 包中。在 WSL 中执行以下命令来安装它
sudo apt update
sudo apt install x11-xserver-utils安装完成后您应该能够使用 xrdb 命令。
3. 接下来创建一个名为.Xresources的文件并在其中添加以下内容
Xft.dpi: 220这将把Xft的dpi设置为220从而放大字体大小。
3. 再次尝试执行 xrdb
安装完 x11-xserver-utils 后您可以重新尝试运行 xrdb
xrdb -merge ~/.Xresources如果没有错误提示并且没有显示任何输出说明 X 资源文件已经成功合并。 总结
如果 xrdb 找不到安装 x11-xserver-utils 包。确保配置的 ~/.Xresources 文件格式正确。使用 xrdb -merge ~/.Xresources 来合并配置文件。
valgrind doc: https://valgrind.org/docs/manual/index.html