AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / coding / 问题

问题[performance](coding)

Martin Hope
Grigory Rechistov
Asked: 2025-04-29 16:13:47 +0800 CST

微基准测试示例,证明代码内联并不总是有利于性能

  • 5

TL;DR:许多资料都提到,过度内联函数有时会因为代码膨胀或其他因素而损害应用程序性能。有没有一个实际的程序示例可以以可衡量的方式证明这一点?


记住,微基准测试的使命是放大程序性能的某些方面。正因如此,任何人都可以轻松生成一个微基准测试,让任何特定问题看起来都像是大问题。// Rico Mariani 的性能花絮

我接触过的许多程序员都认为函数内联对应用程序性能绝对有益。我经常审查的 C/C++ 代码中,函数内联inline(或类似的)关键字被随意地应用于函数,无论其大小、用途、热度或位置如何。

很多情况下,这种奇怪的习惯(这里称之为“内联病” )对整体性能并无害:现代编译器对于哪些代码需要内联有着很好的判断能力,而且很少有代码会因为热度高到让(非)内联产生任何影响。然而,它往往会对最终的软件设计造成损害:更多内容最终会堆积在头文件中,文件不再能够独立编译,等等。

虽然很容易证明,在没有连续基准测试的情况下应用随机内联不会对最终性能产生任何可衡量的差异,但我正在寻找一个极端的例子,强制执行该问题会严格损害性能。

微基准测试就足够了;虽然它无法证明内联对实际应用的任何影响,但它应该能够证明,盲目地强制执行内联并非无条件的好主意。这实际上是几乎所有代码优化过程背后的想法:它可能有帮助,也可能有害,有时甚至没有区别。

此类示例微基准测试的一些要求。

  1. 它应该是一个相当短的程序,最好是用 C 或 C++ 编写的;其他可以强制内联的语言也欢迎。
  2. 它不必是执行任何有用操作的程序,它可能会做一些“愚蠢”的事情只是为了加载/强调底层硬件。
  3. 应该支持两种编译模式:强制内联和禁用内联。可以使用任何技术来实现:条件编译来重新定义内联注解,编译器后端标志来控制内联等等。
  4. 无论在哪一种模式下进行编译,它都应该格式良好并表现出相同的明确定义的行为。
  5. 它应该包含至少两个函数,一个调用另一个函数,目的是影响其中至少一个函数的内联。
  6. 它可能包含任何保证/强制函数内联的技术。例如,可以使用标准inline关键字或编译器特定的扩展(__forceinline等__attribute__ ((always_inline)))来指示编译器执行此操作,无论其判断如何。
  7. 运行时,可以轻松报告性能(延迟、执行时间或类似指标)。它可以仅使用time a.out,也可以在受影响的代码周围内部调用计时工具。
  8. 最后,当由特定版本中的至少一个特定编译器进行编译并在至少一个目标系统上运行时,所得到的程序的两个变体表现出统计上的显著差异,并且强制内联构建比非内联构建更慢。

我确实意识到性能高度依赖于主机参数;在一台机器上较慢的程序在另一台机器上可能会变得同样快甚至更快。但我正在寻找一种最坏的情况,即不受限制的内联显然会适得其反。

理想情况下,不影响内联的其他编译器后端选项(例如整体优化级别等)对于两个构建应该是相同的,以排除可观察到的差异由它们解释而不是由应用/跳过的内联解释的可能性。


我对此类程序的起点有一个想法,但我需要进一步的帮助来充实它:

  1. 内部函数非常庞大,几乎无法放入 CPU 的指令缓存中。
  2. 外部函数足够大,因此,如果将内部函数强制内联到其中,则生成的代码部分将大于 CPU 的指令缓存。
  3. 程序的控制流以这样的方式组织:当所有内容都内联时,它会经历更高频率的指令缓存未命中、缓存刷新或类似事件,如果不强制内联,则不会发生这些事件。
performance
  • 1 个回答
  • 43 Views
Martin Hope
Andranik Chorokhyan
Asked: 2025-04-07 20:38:15 +0800 CST

Hyperledger Caliper - 如何关闭 WebSocket 连接

  • 5

如何关闭Hyperledger Caliper打开的 WebSocket 连接?

我的 config.json 看起来像这样

{
    "caliper": {
        "blockchain": "ethereum"
    },
    "ethereum": {
        "url": "ws://<ws_url>",
        "nonceManager": "managed",
.......
}

看起来每个工作人员都会打开一个 WebSocket 连接,并且即使在成功执行测试后也不会关闭它。

performance
  • 1 个回答
  • 7 Views
Martin Hope
Asigan
Asked: 2025-02-14 11:20:49 +0800 CST

在全局搜索中存储值后,MATLAB 的运行速度明显变慢

  • 6

假设我有一个定义在 0<= x<= pi, 0<=y, z<=2pi 上的函数。我编写了一个 matlab 代码来全局搜索最大点,步长为 0.01。我还恢复了函数值。代码是(当然函数比 x+y+z 更复杂。这只是一个例子。)

x=0;
y=0;
z=0;
i=1;

Maxdeviation= ComputeDeviationSum(0,0,0,mufT, mufD, mufC);
MaximizingArg= [x, y,z] ;
while x<= pi
    y=0;
    z=0;
    while y<= 2*pi
        z=0;
        while z<=2 *pi
            deviation= x+y+z; % Just an example. The function is more complex.
            if deviation> Maxdeviation
                MaximizingArg= [x, y,z];
                Maxdeviation= deviation;
            end
            a(i,:)=[x, y,z, deviation];
            z=z+0.01;
            i=i+1;
        end
        y=y+0.01;
    end
    x=x+ 0.01;
end

我发现这真的很慢。在我删除了三行恢复值之后,即删除

i=1;
a(i,:)=[x, y,z, deviation];
i=i+1

这三行代码,速度就快了很多。(我在 20 秒后停止了执行,发现后者比前者多执行了 10 倍的迭代次数。)

我的问题是:为什么停止恢复值后,代码会快得多?如果我想为每个点恢复值,我该怎么做才能让代码更快?

performance
  • 1 个回答
  • 38 Views
Martin Hope
NoBullsh1t
Asked: 2025-02-10 03:05:25 +0800 CST

创建闭包与创建结构的性能损失是多少?

  • 7

我做了一些看起来很聪明的事情。为了更好地处理错误,我编写了如下 DB 操作

    fn handle_delete(&self, id: &Id) -> Result<(), SqliteError> {
        db_op(
            || DbOperationInfo::new("filerequests", OperationType::Delete),
            || {
                self.conn
                    .execute("DELETE FROM filerequests WHERE id = ?", [id.to_string()])?;
                Ok(())
            },
        )
    }

我的想法是,我有我的 SqliteError 枚举,它包含一个相当小的结构,其中包含有关尝试的操作及其rusqlite::error::Error原因的一些信息。

该db_op函数的作用是接受两个闭包,第一个闭包生成包含操作信息的小结构,第二个闭包执行实际操作。如果(且仅当)发生错误,则执行第一个闭包生成操作信息,然后添加导致错误的代码以创建SqliteError。

因此操作信息的创建是懒惰的。

但是我在这里真的有收获吗?还是创建闭包的成本同样高昂?或者,也许编译器会优化闭包创建并只执行一次?或者也许它会同样优化结构创建(内容有点静态)?

在此寻求一些指导:这种优化(可能)真的有帮助吗?

performance
  • 1 个回答
  • 49 Views
Martin Hope
Marmite Bomber
Asked: 2025-02-09 05:17:52 +0800 CST

两个哈希图的性能比较

  • 6

我在 Groovy 中对两个哈希图进行比较,如下例所示

 h1 = [key1 : [att1 : 1, att2 : 2], key2 : [att1 : 10, att2 : 20], key3 : [att1 : 3, att2 : 4]]
 h2 = [key1 : [att1 : 1, att2 : 3], key2 : [att1 : 10, att2 : 20]]

我需要如下结果

 [key1:[att1:true, att2:false], key2:[att1:true, att2:true], key3:[att1:false, att2:false]]
 

即,如果给定键的属性匹配,则应将其标记为true,如果它们不匹配或第二个源中缺少该键,则应将其设置为false

我尝试了这个嵌套的闭包,

 diff = h1.collectEntries {key, value -> [key,  (value.collectEntries {k, v -> [k, (v == (h2[key] ? h2[key][k] : null) ) ] } ) ] }

它可以工作,但是对于大地图比例来说效果不佳,Groovy 中是否有更好的解决方案?

请注意,如果这可能相关,则属性在所有情况下都是相同的并且是提前知道的。

performance
  • 1 个回答
  • 32 Views
Martin Hope
Will Calderwood
Asked: 2025-02-05 01:35:56 +0800 CST

使用 Next.js 在移动设备上的最大内容绘制非常慢

  • 5

我正在开发一个网站https://www.paveinsight.com。该网站使用 Next.js 编写并托管在 Vercel 上,主页生成为静态页面。

运行 PageSpeed Insights 时,我的 LCP 很慢,在移动设备上尤其慢,我不知道原因。图片经过优化,根据屏幕调整大小并托管在 Amazon CloudFront 上。在我的实际设备上测试,页面加载速度很快,而且很流畅。在我的 Pixel 7 上加载的 webp 图片为 81KB,但 PageSpeed Insights 表示 LCP 在移动设备上为 9.4 秒。

模拟的 4G 连接速度为 1,638 kb/s,因此我预计下载时间将远少于 1 秒。下面是所用时间的明细。什么可能导致 TTFB 过高,或极端的加载延迟和渲染延迟?

TTFB 6% 600ms
Load delay 53% 4,920ms
Load time 1% 80ms
Render delay 40% 3,750ms

在此处输入图片描述

performance
  • 1 个回答
  • 27 Views
Martin Hope
GregTheMadMonk
Asked: 2024-11-22 21:07:28 +0800 CST

perf report:理解第一行输出

  • 5

我正在寻找答案,但没有找到明确的答案。我该如何解释perf report输出中的第一行。它是这样的:

Samples: 173M of event 'cache-misses', Event count (approx.): 461731712088

我看过的几乎每个教程都讲到了所有内容,除了第一行。本页解释了样本和计数之间的区别,但我想 100% 确保我没有得出错误的结论:在我的例子中,173M和461731712088是什么意思?从我读到的内容来看,我猜第二个是运行时发生的缓存未命中总数,第一个是记录并用于显示统计信息的缓存未命中数。这是正确的还是我误解了输出?

performance
  • 1 个回答
  • 28 Views
Martin Hope
Al John
Asked: 2024-11-21 23:05:39 +0800 CST

我应该在 MAUI 中使用哪种 StackLayout 类型?

  • 6

就我使用 MAUI 的经验而言,我只使用<VerticalStackLayout/>和<HorizontalStackLayout/>来水平或垂直定位子元素。

我很少或几乎从来不用,<StackLayout/>因为我读到过它的性能可能会稍差一些。

什么时候建议使用<StackLayout/>和调整其Orientation属性?

我应该使用...

<StackLayout Orientation="Horizontal">
<StackLayout/>

<StackLayout Orientation="Vertical">
<StackLayout/>

...而不是...

<HorizontalStackLayout>
<HorizontalStackLayout/>

<VerticalStackLayout>
<VerticalStackLayout/>

...或者反过来,取决于不同的情况?

performance
  • 1 个回答
  • 15 Views
Martin Hope
user3163495
Asked: 2024-10-18 22:53:30 +0800 CST

CPU 是否有硬件“数学缓存”或字典来存储简单数学运算的结果以便更快地处理?

  • 8

对于简单的数学运算,例如sqrt(2),,,,,1 / 2等等, CPU 是否包含某种硬件表,其中包含这些运算的结果,因此它们实际上不是“1 + 1计算”的,而是从某种字典或“数学缓存”中获取的,以便更快地处理?当然,我预计有些人会问“谁来定义什么是‘简单’数学运算?”,但我只是很好奇。10^21 * 0tan(45)

performance
  • 1 个回答
  • 95 Views
Martin Hope
ilja
Asked: 2024-09-20 20:00:09 +0800 CST

为什么多个相同的函数调用在Arduino上的执行时间有明显差异?

  • 5

我在 Arduino 上编写了我的类的成员函数Adf,bool Adf::sendAndReceive(char *data, uint8_t length)该函数通过指向的串行端口发送一个字符数组Adf::pSerial,然后读取 rx 缓冲区。rx 和 tx 线路已连接,因此每个发送的字节都会回显到 rx 缓冲区中。此外,我使用ArduinoLog库来跟踪整个流量。现在我遇到了一个非常奇怪的情况:我sendAndReceive使用相同的参数连续两次调用,在第一次调用期间,记录传出消息花费不到 1 毫秒,但在第二次调用中花费了 29 毫秒。

为什么使用相同的参数调用相同的函数会花费不同的时间?

这些是被调用的函数:

bool Adf::sendAndReceive(char *data, uint8_t length)
{
  uint8_t rxTxLength = 0;

  // send data
  unsigned long start = millis();
  rxTxLength = pSerial->write(data, length);
  unsigned long end = millis();
  Logger.trace("TX start: %lu, end: %lu, duration: %lu\n", start, end, end - start);

  // STRANGE BEHAVIOUR HAPPENS HERE ===================
  unsigned long start2 = millis();
  // Trace the sent bytes
  Logger.trace("%s - data: ", __func__);
  traceCharArray(data, rxTxLength);
  unsigned long end2 = millis();
  Logger.trace("Trace start: %lu, end: %lu, duration: %lu\n", start2, end2, end2 - start2);
  // ==================================================

  // handle write error
  unsigned long start3 = millis();
  if (rxTxLength != length)
  {
    Logger.errorln("%s - Error writing to serial. Only %d of %d bytes written.",
                    __func__,
                    rxTxLength,
                    length);
    return false; // Failure: error writing to serial
  }
  unsigned long end3 = millis();
  Logger.trace("Error start: %lu, end: %lu, duration: %lu\n", start3, end3, end3 - start3);

  // Read all echoed bytes
  unsigned long start4 = millis();
  char echo[length];
  getAdfResponse(echo, length);
  unsigned long end4 = millis();
  Logger.trace("Echo start: %lu, end: %lu, duration: %lu\n", start4, end4, end4 - start4);

  // Compare sent and echoed bytes
  unsigned long start5 = millis();
  if (memcmp(data, echo, length) != 0)
  {
    Logger.errorln("%s - Serial was not echoed correctly", __func__);
    return false; // Failure: echoed bytes do not match sent bytes  
  }
  unsigned long end5 = millis();
  Logger.trace("Compare start: %lu, end: %lu, duration: %lu\n", start5, end5, end5 - start5);
  return true; // Success: all bytes echoed correctly
}

void Adf::traceCharArray(char *data, uint8_t length)
{
  for (int i = 0; i < length; i++)
  {
    Logger.trace("%x, ", static_cast<unsigned char>(data[i])); 
    /* static cast to ensure that the data is correctly interpreted as an 
    ** unsigned value when logging in hexadecimal format */
  }
  Logger.traceln("");
}

Adf::traceCharArray问题发生在调用该函数的“Trace”部分。

这是主文件

#include <Arduino.h>
#include <ADF.h>

#define ADDRESS_WIRE 33
#define BAUD_RATE    2400

Adf adf(ADDRESS_WIRE, &Wire1, BAUD_RATE, &Serial3);
char msg = 0x81;

void setup()
{
  // initialize Serial
  Serial.begin(9600);
  Serial.println("Hello ADF");

  adf.Logger.begin(LOG_LEVEL_TRACE, &Serial, false);

  // initialize ADF
  if (!adf.begin())
  {
    Serial.println("Init failed.");
  }

  if (!adf.sendAndReceive(&msg, 1))
  {
    Serial.println("sendAndReceive failed.");
  }
  Serial.println("====================================");
  if (!adf.sendAndReceive(&msg, 1))
  {
    Serial.println("sendAndReceive failed.");
  }


  // signal setup OK
  Serial.println("Setup done.");
}

void loop()
{

}

这是 Logger 打印的输出(以及我的注释​​):

---- Opened the serial port COM3 ----
13:29:10:875 -> Hello ADF
13:29:16:384 -> TX start: 5513u, end: 5513u, duration: 0u
13:29:16:429 -> sendAndReceive - data: 81, 
13:29:16:458 -> Trace start: 5513u, end: 5513u, duration: 0u <--- compare this
13:29:16:503 -> Error start: 5513u, end: 5513u, duration: 0u
13:29:16:552 -> getAdfResponse - resp: 81, 
13:29:16:581 -> Echo start: 5545u, end: 5574u, duration: 29u
13:29:16:626 -> Compare start: 5621u, end: 5621u, duration: 0u
13:29:16:677 -> ====================================
13:29:16:716 -> TX start: 5709u, end: 5709u, duration: 0u
13:29:16:761 -> sendAndReceive - data: 81, 
13:29:16:790 -> Trace start: 5753u, end: 5782u, duration: 29u <--- to this
13:29:16:835 -> Error start: 5830u, end: 5830u, duration: 0u
13:29:16:884 -> getAdfResponse - resp: 81, 
13:29:16:913 -> Echo start: 5877u, end: 5906u, duration: 29u
13:29:16:958 -> Compare start: 5953u, end: 5953u, duration: 0u
13:29:17:007 -> Setup done.

问题Adf::traceCharArray:为什么即使传递了相同的参数,第一次调用也需要0ms,而第二次调用却需要 29ms?


注意:经过进一步研究,我发现如果Adf::traceCharArray直接调用(而不是从另一个函数中调用),则不会发生此问题:

在主文件中

  unsigned long start = millis();
  adf.traceCharArray(&msg, 1);
  unsigned long end = millis();
  Serial.print("duration: ");
  Serial.println(end - start);
  Serial.println("====================================");
  unsigned long start2 = millis();
  adf.traceCharArray(&msg, 1);
  unsigned long end2 = millis();
  Serial.print("duration: ");
  Serial.println(end2 - start2);

输出

---- Opened the serial port COM3 ----
13:46:12:418 -> Hello ADF
13:46:17:927 -> 81, 
13:46:17:935 -> duration: 0
13:46:17:958 -> ====================================
13:46:17:988 -> 81, 
13:46:17:992 -> duration: 0
13:46:18:004 -> Setup done.

编辑:我发现问题仍然存在,即使traceCharArray(data, rxTxLength);注释掉了对的调用。因此,该行的执行时间Logger.trace("%s - data: ", __func__);在 0 到 29ms 之间变化。

performance
  • 1 个回答
  • 17 Views

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    重新格式化数字,在固定位置插入分隔符

    • 6 个回答
  • Marko Smith

    为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会?

    • 2 个回答
  • Marko Smith

    VScode 自动卸载扩展的问题(Material 主题)

    • 2 个回答
  • Marko Smith

    Vue 3:创建时出错“预期标识符但发现‘导入’”[重复]

    • 1 个回答
  • Marko Smith

    具有指定基础类型但没有枚举器的“枚举类”的用途是什么?

    • 1 个回答
  • Marko Smith

    如何修复未手动导入的模块的 MODULE_NOT_FOUND 错误?

    • 6 个回答
  • Marko Smith

    `(表达式,左值) = 右值` 在 C 或 C++ 中是有效的赋值吗?为什么有些编译器会接受/拒绝它?

    • 3 个回答
  • Marko Smith

    在 C++ 中,一个不执行任何操作的空程序需要 204KB 的堆,但在 C 中则不需要

    • 1 个回答
  • Marko Smith

    PowerBI 目前与 BigQuery 不兼容:Simba 驱动程序与 Windows 更新有关

    • 2 个回答
  • Marko Smith

    AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String”

    • 1 个回答
  • Martin Hope
    Fantastic Mr Fox msvc std::vector 实现中仅不接受可复制类型 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant 使用 chrono 查找下一个工作日 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor 构造函数的成员初始化程序可以包含另一个成员的初始化吗? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský 为什么 C++20 概念会导致循环约束错误,而老式的 SFINAE 不会? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul C++20 是否进行了更改,允许从已知绑定数组“type(&)[N]”转换为未知绑定数组“type(&)[]”? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann 为什么 {2,3,10} 和 {x,3,10} (x=2) 的顺序不同? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller 在 5.2 版中,bash 条件语句中的 [[ .. ]] 中的分号现在是可选的吗? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench 为什么双破折号 (--) 会导致此 MariaDB 子句评估为 true? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng 为什么 `dict(id=1, **{'id': 2})` 有时会引发 `KeyError: 'id'` 而不是 TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob:MobileAds.initialize() - 对于某些设备,“java.lang.Integer 无法转换为 java.lang.String” 2024-03-20 03:12:31 +0800 CST

热门标签

python javascript c++ c# java typescript sql reactjs html

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve