什么更快:
add DWORD PTR [rbp-0x4],1
Run Code Online (Sandbox Code Playgroud)
或者
mov eax,DWORD PTR [rbp-0x4]
add eax,1
mov DWORD PTR [rbp-0x4],eax
Run Code Online (Sandbox Code Playgroud)
我已经看到编译器生成的第二个代码,所以也许调用add寄存器要快得多?
我可以使用volatile类似以下的内容,其中的值可能会被外部函数/信号/等修改:
volatile int exit = 0;
while (!exit)
{
/* something */
}
Run Code Online (Sandbox Code Playgroud)
并且编译器/程序集不会缓存该值。另一方面,使用restrict关键字,我可以告诉编译器一个变量没有别名/只在当前范围内被引用一次,编译器可以尝试优化它:
void update_res (int *a , int *b, int * restrict c ) {
* a += * c;
* b += * c;
}
Run Code Online (Sandbox Code Playgroud)
这是对两者的正确理解,它们基本上是彼此对立的吗?volatile说该变量可以在当前范围之外修改并restrict说它不能?对于使用这两个关键字的最基本示例,它将发出的汇编指令示例是什么?
我对汇编有一点了解。那么我先介绍一下代码,然后解释一下我的思路。
#This is the Assembly version.
pushq %rbp
movq %rsp, %rbp
movl $2, -4(%rbp)
movl $3, -8(%rbp)
movl $5, %eax
popq %rbp
ret
#This is the C version.
int twothree() {
int a = 2;
int b = 3;
return 2 + 3;
}
Run Code Online (Sandbox Code Playgroud)
好吧,首先让我吃惊的是我们没有将变量 a 和 b 用作 a + b。所以它们是不必要的,我们直接将整数相加。然而,如果计算机能够理解这一点,我想那将是非常可怕的。所以,我的问题是:在没有任何 addl 或类似命令的情况下,这个汇编代码是如何工作的?我们直接将立即数(或常量)整数 5 移至 eax 注册器。
另外,快速提问。那么最后两行之后的 a 和 b 变量会发生什么情况呢?它们在堆栈中的位置(或者也许我们可以将它们用作内存位置的“注册器”称为“注册器”)现在是空闲的,因为我们使用 malloc + free。这是真的还是至少合乎逻辑?我猜 popq %rbp 是关闭堆栈的命令。
正如我所说,我不是汇编专家。所以这些想法大部分都只是思考。谢谢!
重新发帖原因:
本来我只得到一个回复,只是指出标题夸大了。因此,再试一次,也许这次会有更多的人看到这个问题,因为我真的不知道还能看哪里......我会确保删除原来的问题以避免重复,并保留这个新问题。我并不是想向论坛发送垃圾邮件。
请随意在编辑时删除上面的文本,我只是想解释为什么我要重新发布 - 但这并不是问题的一部分。
所以,最初的问题是:
我的程序中有一些函数在 Visual Studio Community,2015 中的调试模式下运行速度非常慢。它们是用于“索引”3D 模型顶点的函数。
通常情况下,我准备好调试模式会慢一点,可能慢 2 -3 倍。但...
在发布模式下,程序将在大约2 - 3 秒内启动并索引模型。完美的。
然而,在调试模式下,我的程序需要7 分钟以上才能真正响应、开始渲染并接受输入。它在索引一个模型时卡住了七分钟多。在此期间程序完全冻结。
相同的模型在“发布”模式下加载和索引只需不到 3秒。调试过程中怎么可能花费如此长的时间?
调试和发布模式都是标准的开箱即用模式。我不记得更改过其中任何一个的任何设置。
以下是在调试模式下减慢程序速度的代码:
// Main Indexer Function
void indexVBO_TBN(
std::vector<glm::vec3> &in_vertices,
std::vector<glm::vec2> &in_uvs,
std::vector<glm::vec3> &in_normals,
std::vector<glm::vec3> &in_tangents,
std::vector<glm::vec3> &in_bitangents,
std::vector<unsigned short> & out_indices,
std::vector<glm::vec3> &out_vertices,
std::vector<glm::vec2> &out_uvs,
std::vector<glm::vec3> &out_normals,
std::vector<glm::vec3> &out_tangents,
std::vector<glm::vec3> &out_bitangents){
int count = 0;
// For each input vertex
for (unsigned int i = …Run Code Online (Sandbox Code Playgroud) 我潜伏在我的操作系统教科书中,它提到可以在数据断点上实现虚拟地址转换(用于程序调试)。我只知道调试器使用 INT 3 来暂停正在调试控制和地址寄存器中以某种方式处理的程序、局部和全局变量。但是经过一番挖掘,我只找到了有关使用调试寄存器的线性地址的信息。根本没有关于虚拟地址相关数据断点背后机制的文章或讨论。那么这究竟是如何工作的呢?
我正在分析我的应用程序的核心转储,当我转到第 1 帧时,我打印了存储在 EAX 中的变量的值。Gdb 打印值,如果是真的,程序不会调用 panic(反汇编显示,它比较寄存器中的值,所以没有其他线程可以改变它)。我调用info reg了指令指针的一部分,对于帧 #0 和 #1 给了我相同的结果。是否有可能 Gdb 在帧 #1 中显示帧 #0 的寄存器 EAX 的值?
编辑:代码看起来像这样:
switch(myVar){
case -1:
break;
default:
panic();
}
Run Code Online (Sandbox Code Playgroud)
gdb 显示:
(gdb) bt
#0 panic()
#1 0x0891a3e9 in myFunc() at myFunc.c:10
(gdb) up
#1 0x0891a3e9 in myFunc() at myFunc.c:10
10 panic();
(gdb) print myVar
$1 = -1
(gdb) print &myVar
Address requested for identifier "myVar" which is in register $eax
Run Code Online (Sandbox Code Playgroud) 我用 C 编写了众所周知的交换函数,并使用 gcc S 观看了汇编输出,并再次做了同样的事情,但对 O2 进行了优化
差异非常大,因为与 20 行相比,我只看到了 5 行。
我的问题是,如果优化真的有帮助,为什么不一直使用它?为什么我们非优化编译代码?
给业内人士一个额外的问题,当您在测试后发布程序的最终版本时,您是否进行了优化编译?
我正在回复您的所有评论,请阅读。
抱歉,我一直不明白这里的规则。我已经删除了所有重复的帖子。这是第一个相关问题。\n请不要将此帖子标记为我另一篇帖子的重复(执行次数减少 3 倍,但执行效率几乎不变。在 C 中),即使代码有些相似,他们提出了截然不同的问题。这也是我同一天发现的两个问题。类似的帖子因“误判”而被重复,然后被关闭。可能是我没有把这个问题说清楚。我真的很希望得到答案,所以我重新发布了它。希望大家能够看清问题,非常感谢!
\n在下面的C代码中,我在第一次测试时间的循环中添加了一个“if”语句,执行时间完全相同。从理论上讲,它应该更慢。尽管分支预测可以使它们的性能几乎相同,但它实际上变得更快。这是什么原理呢?我尝试使用clang和gcc编译器分别在Mac和Linux环境中运行,并尝试了各种优化级别。为了防止缓存受到影响,我让速度较快的先执行,但有冗余代码的循环执行得更快。
\n如果您认为我的描述不可信,请将以下代码编译到您的计算机中并运行。希望有人能为我回答这个问题\xef\xbc\x8c谢谢。
\nC代码:
\n#include <stdio.h>\n#include <time.h>\n#include <stdlib.h>\n#include <string.h>\n\n#define TLen 300000000\n#define SLen 10\n\nint main(int argc, const char * argv[]) {\n srandom((unsigned)time(NULL));\n \n // An array to increase the index,\n // the range of its elements is 1-256\n int rand_arr[128];\n for (int i = 0; i < 128; ++i)\n rand_arr[i] = random()%256+1;\n \n // A random text(very long), the range of its elements is 0-127\n char *tex = malloc((sizeof *tex) * …Run Code Online (Sandbox Code Playgroud) 有人说,在大多数情况下,编译器比人类更聪明,并且会优化很多我们无法明确执行的东西。我想知道编译器是否对此进行了优化。下面的代码有有趣的结果,但没有错误。但有一个严重的问题。
//will this move or copy construct?
#include <iostream>
class A
{
public:
A()
{
std::cout << "Constructed A.\n";
}
~A()
{
std::cout << "A destroyed.\n";
}
};
class B
{
private:
A m_A;
public:
B(A someA):m_A{someA}
{
}
};
int main()
{
B oneB{A()};
return 0;
}
Run Code Online (Sandbox Code Playgroud)
此代码使用 Clang++ 13.0.1 在 Windows 10 上打印-fexceptions -O3 -Wall -g -std=c++20 -v -c
Constructed A.
A destroyed.
A destroyed.
Run Code Online (Sandbox Code Playgroud)
为什么A被销毁了两次但只被构造了一次?B即使使用常量引用构建时也会发生这种情况。这真是太荒谬了。我仍在学习 C++,从未参与过任何项目或其他任何事情。我想问一些我在网上学习时感到困惑的事情。
在下面的代码中,
int firstFunction(int& refParam)
{
std::cout << "Type of refParam is: " << typeid(refParam).name() << '\n';
return refParam;
}
int secondFunction(int param)
{
std::cout << "Type of param is: " << typeid(param).name() << '\n';
return param;
}
int main()
{
int firstVar{ 1 };
int secondVar{ firstFunction(firstVar) };
int thirdVar{ secondFunction(firstVar) };
}
Run Code Online (Sandbox Code Playgroud)
控制台输出是
int
int
Run Code Online (Sandbox Code Playgroud)
当我检查Godbolt 链接中的汇编代码时。
firstFunction(int&):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax] …Run Code Online (Sandbox Code Playgroud)