- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
用确定井字棋盘结果的玩具程序进行测试,我明白了。是什么造成了如此大的差异?我怀疑使用静态链接的 libc 调用 rand
会更快,但仍然对结果感到惊讶。
~$ gcc a.c -std=c11 -O3
~$ time ./a.out
32614644
real 0m9.396s
user 0m9.388s
sys 0m0.004s
~$ gcc a.c -std=c11 -O3 -static
~$ time ./a.out
32614644
real 0m6.891s
user 0m6.884s
sys 0m0.000s
#include <stdio.h>
#include <stdlib.h>
#define SIZE 3
#define SIZE_2 (SIZE * SIZE)
static int determineResult(int board[static SIZE_2]) {
for (int i = 0; i < SIZE_2; i += SIZE) {
if (!board[i]) {
continue;
}
for (int j = i + 1; j < i + SIZE; ++j) {
if (board[i] != board[j]) {
goto next;
}
}
return board[i];
next:;
}
for (int i = 0; i < SIZE; ++i) {
if (!board[i]) {
continue;
}
for (int j = i + SIZE; j < i + SIZE_2; j += SIZE) {
if (board[i] != board[j]) {
goto next2;
}
}
return board[i];
next2:;
}
for (int i = SIZE + 1; i < SIZE_2; i += SIZE + 1) {
if (board[i] != *board) {
goto next3;
}
}
return *board;
next3:
for (int i = SIZE * 2 - 2; i <= SIZE_2 - SIZE; i += SIZE - 1) {
if (board[i] != board[SIZE - 1]) {
return 0;
}
}
return board[SIZE - 1];
}
#define N 50000000
int main(void) {
srand(0);
size_t n = 0;
for (int i = 0; i < N; ++i) {
int board[SIZE_2];
for (int i = 0; i < SIZE_2; ++i) {
board[i] = rand() % 3;
}
n += determineResult(board);
}
printf("%zu\n", n);
return EXIT_SUCCESS;
}
最佳答案
在不知道您的系统使用的特定 ABI(取决于操作系统和 CPU 架构)的情况下,我无法确定这是原因,但以下是最可能的解释。
在大多数实现中,共享库(包括共享 libc.so
)中的代码必须是位置无关代码。这意味着它可以在任何地址加载(而不是由链接器分配一个固定的运行时地址),因此不能在机器代码中使用硬编码的绝对数据地址。相反,它必须通过指令指针相对寻址或全局偏移表 (GOT) 访问全局数据,其地址要么保存在寄存器中,要么相对于指令指针进行计算。这些寻址模式主要在设计良好的现代指令集架构(如 x86_64、AArch64、RISC-V 等)上有效。在大多数其他架构(包括 32 位 x86)上,它们的效率非常低。例如下面的函数:
int x;
int get_x()
{
return x;
}
在 x86 上会像下面这样膨胀:
get_x:
push %ebp
mov %esp, %ebp
push %ebx
sub $4, %esp
call __x86.get_pc_thunk_bx
add $_GLOBAL_OFFSET_TABLE_, %ebx
mov x@GOT(%ebx), %eax
mov (%eax),%eax
add $4, %esp
pop %ebx
pop %ebp
ret
而您希望(对于非位置无关代码)看到:
get_x:
mov x, %eax
ret
由于随机数生成器具有内部(全局)状态,因此他们不得不为与位置无关的代码执行这种昂贵的舞蹈。由于他们所做的实际计算可能非常短且快速,因此 PIC 开销可能是他们运行时间的重要部分。
证实这一理论的一种方法是尝试使用 rand_r
或 random_r
代替。这些函数使用调用者提供的状态,因此可以(至少在理论上)避免对全局数据的任何内部访问。
关于c - 为什么动态链接的可执行文件明显比 Linux 中的静态链接的慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32544984/
通常当我请求线程转储时,系统性能不佳的症状很容易解释;也就是说,通常我会看到许多线程显然正在等待一个已被获取但未被另一个释放的监视器。 在这种情况下,我有很多线程在等待监视器 (0x965ad100)
C:\Users\shagy\Desktop\3RD YEAR 2ND SEMESTER\SPM\Newfolder\SPM-SMS>npm start npm ERR! path C:\Users\
我是一名优秀的程序员,十分优秀!