template <typename TAG>
fn(int left, TAG, int right)
{
}
fn(0, some_type_tag(), 1);
/* or */
fn(0,int(), 1); // where the primitive, int, is not empty.
Run Code Online (Sandbox Code Playgroud)
编辑:这个问题有两个视角.
/编辑
我的标签通常是空结构,但是在我的代码的某些部分,它们是原始类型的typedef.所以,我很想知道现代编译器是否会实际传递参数.这有两个方面.
让我们把它保持到gcc 4.5和msvc 2008+
这只是一个帮助我更好地理解CSS渲染的问题.
可以说我们有一百万行.
<div class="first">
<div class="second">
<span class="third">Hello World</span>
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
哪个是将Hello World字体更改为红色的最快方法?
.third { color: red; }
div.third { color: red; }
div.second div.third { color: red; }
div.first div.second div.third { color: red; }
Run Code Online (Sandbox Code Playgroud)
此外,如果中间的标签有唯一ID"foo",该怎么办?以上哪种CSS方法最快.
我知道为什么这些方法被使用等,我只是想更好地掌握浏览器的渲染技术,我不知道如何进行测试时间.
更新:很好的回答Gumbo.从它的外观来看,在常规站点中更快地完成标签的完整定义.因为它找到了父母并缩小了对找到的每个父母的搜索范围.
从某种意义上说,你可能会有一个非常大的CSS文件.
在循环中声明一个变量是不好的做法?在我看来,这样做,如下面的第一个代码块所示,将使用十倍的内存作为第二个...由于在循环的每次迭代中创建一个新的字符串.它是否正确?
for (int i = 0; i < 10; i++) {
String str = "Some string";
}
Run Code Online (Sandbox Code Playgroud)
与
String str;
for (int i = 0; i < 10; i++) {
str = "Some String";
}
Run Code Online (Sandbox Code Playgroud) 我正在ARM Cortex M0上做一个项目,它不支持未对齐(4字节)访问,我正在尝试优化未对齐数据的操作速度.
我将蓝牙低功耗访问地址(48位)作为6字节数组存储在一些作为数据包缓冲区的打包结构中.由于打包,BLE地址不一定从字对齐的地址开始,并且在优化我对这些地址的访问功能时遇到了一些复杂问题.
第一种也是最明显的方法是对数组中每个字节单独运行的for循环.例如,检查两个地址是否相同可以这样做:
uint8_t ble_adv_addr_is_equal(uint8_t* addr1, uint8_t* addr2)
{
for (uint32_t i = 0; i < 6; ++i)
{
if (addr1[i] != addr2[i])
return 0;
}
return 1;
}
Run Code Online (Sandbox Code Playgroud)
我在我的项目中做了很多比较,我想看看是否可以从这个功能中挤出更多的速度.我意识到对于对齐的地址,我可以将它们转换为uint64_t,并与应用的48位掩码进行比较,即
((uint64_t)&addr1[0] & 0xFFFFFFFFFFFF) == ((uint64_t)&addr2[0] & 0xFFFFFFFFFFFF)
Run Code Online (Sandbox Code Playgroud)
可以对写入进行类似的操作,并且它适用于对齐版本.但是,由于我的地址并不总是字对齐(甚至是半字),所以我必须做一些额外的技巧来完成这项工作.
首先,我想出了编译器宏的未经优化的噩梦:
#define ADDR_ALIGNED(_addr) (uint64_t)(((*((uint64_t*)(((uint32_t)_addr) & ~0x03)) >> (8*(((uint32_t)_addr) & 0x03))) & 0x000000FFFFFFFF)\
| (((*((uint64_t*)(((uint32_t)_addr+4) & ~0x03))) << (32-8*(((uint32_t)_addr) & 0x03)))) & 0x00FFFF00000000)
Run Code Online (Sandbox Code Playgroud)
它基本上将整个地址移位到前一个字对齐的存储器位置,而不管偏移量.例如:
0 1 2 3
|-------|-------|-------|-------|
|.......|.......|.......|<ADDR0>|
|<ADDR1>|<ADDR2>|<ADDR3>|<ADDR4>|
|<ADDR5>|.......|.......|.......|
Run Code Online (Sandbox Code Playgroud)
变
0 1 2 3
|-------|-------|-------|-------|
|<ADDR0>|<ADDR1>|<ADDR2>|<ADDR3>|
|<ADDR4>|<ADDR5>|.......|.......|
|.......|.......|.......|.......| …Run Code Online (Sandbox Code Playgroud) 完全知道这些完全人为的基准测试并不重要,但我对"大4"编译器选择编写一个简单的片段的几种方式感到有点惊讶.
struct In {
bool in1;
bool in2;
};
void foo(In &in) {
extern bool out1;
extern bool out2;
out1 = (in.in1 == true);
out2 = in.in2;
}
Run Code Online (Sandbox Code Playgroud)
注意:所有编译器都设置为x64模式,具有最高的"通用"(=没有指定特定的处理器体系结构)"优化速度"设置; 你可以通过自己看到的结果/和他们一起玩了,在https://gcc.godbolt.org/z/K_i8h9)
带有-O3的Clang 6似乎产生了最直接的输出:
foo(In&): # @foo(In&)
mov al, byte ptr [rdi]
mov byte ptr [rip + out1], al
mov al, byte ptr [rdi + 1]
mov byte ptr [rip + out2], al
ret
Run Code Online (Sandbox Code Playgroud)
在符合标准的C++程序中,== true比较是多余的,因此两个分配都成为从一个内存位置到另一个内存位置的直接副本,al因为内存没有内存mov.
但是,由于这里没有寄存器压力,我原本期望它使用两个不同的寄存器(完全避免两个赋值之间的错误依赖链),可能先启动所有读操作,然后执行所有写操作,以帮助指令级并行; 由于寄存器重命名和积极无序的CPU,这种优化是否已经完全淘汰了最近的CPU?(稍后会详细介绍)
带有-O3的GCC 8.2 …
考虑向下转换unsigned为的精简示例unsigned char,
void unsigned_to_unsigned_char(unsigned *sp, unsigned char *dp)
{
*dp = (unsigned char)*sp;
}
Run Code Online (Sandbox Code Playgroud)
上面的 C 代码被翻译成汇编代码,gcc -Og -S如下所示
movl (%rdi), %eax
movb %al, (%rsi)
Run Code Online (Sandbox Code Playgroud)
出于什么原因,C 到汇编的翻译不是如下所示?
movb (%rdi), %al
movb %al, (%rsi)
Run Code Online (Sandbox Code Playgroud)
是因为这是不正确的,还是因为比movl它更传统或更短的编码movb?
我一直在寻找一些Java基本集合(的宝库,fastutil,HPPC)和我已经注意到,类变量有时声明为图案final的局部变量.例如:
public void forEach(IntIntProcedure p) {
final boolean[] used = this.used;
final int[] key = this.key;
final int[] value = this.value;
for (int i = 0; i < used.length; i++) {
if (used[i]) {
p.apply(key[i],value[i]);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我已经完成了一些基准测试,看起来这样做会稍快一点,但为什么会这样呢?我试图理解如果函数的前三行被注释掉,Java将采取哪些不同的做法.
注意:这似乎与这个问题类似,但这是针对c ++的,并没有说明它们被声明的原因final.
我遇到了这个问题,它比较了各种编译器在计算斐波那契数字时的表现.
我尝试用Haskell做这个,看看它与C的比较.
C代码:
#include <stdio.h>
#include <stdlib.h>
int fib (int n) {
if (n < 2) return 1;
return fib (n-1) + fib (n-2);
}
int main (int argc, char* argv[]) {
printf ("%i\n", fib (atoi(argv[1])));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
结果:
> gcc -O3 main.c -o fib
> time ./fib 40
165580141
real 0m0.421s
user 0m0.420s
sys 0m0.000s
Run Code Online (Sandbox Code Playgroud)
哈斯克尔:
module Main where
import System.Environment (getArgs)
fib :: Int -> Int
fib n | n < 2 = 1
| …Run Code Online (Sandbox Code Playgroud) 我的表格中有很多范围[(1, 1000), (5000, 5678), ... ].我正试图找出检查数字是否在任何范围内的最快方法.范围由longs并且太大而不能保留set所有数字.
最简单的解决方案是:
ranges = [(1,5), (10,20), (40,50)] # The real code has a few dozen ranges
nums = range(1000000)
%timeit [n for n in nums if any([r[0] <= n <= r[1] for r in ranges])]
# 1 loops, best of 3: 5.31 s per loop
Run Code Online (Sandbox Code Playgroud)
榕树有点快:
import banyan
banyan_ranges = banyan.SortedSet(updator=banyan.OverlappingIntervalsUpdator)
for r in ranges:
banyan_ranges.add(r)
%timeit [n for n in nums if len(banyan_ranges.overlap_point(n))>0]
# 1 loops, best of …Run Code Online (Sandbox Code Playgroud) 是什么原因导致ARM上的GCC 7.2.1使用来自memory(lr)的负载来处理某些常量,以及mov在某些其他情况下使用immediate()?具体来说,我看到以下内容:
用于ARM的GCC 7.2.1编译:
extern void abc(int);
int test() { abc(1199); return 0; }
Run Code Online (Sandbox Code Playgroud)
......进入那个:
test():
push {r4, lr}
ldr r0, .L4 // ??!
bl abc(int)
mov r0, #0
pop {r4, lr}
bx lr
.L4:
.word 1199
Run Code Online (Sandbox Code Playgroud)
还有这个:
extern void abc(int);
int test() { abc(1200); return 0; }
Run Code Online (Sandbox Code Playgroud)
......进入那个:
test():
push {r4, lr}
mov r0, #1200 // OK
bl abc(int)
mov r0, #0
pop {r4, lr}
bx lr
Run Code Online (Sandbox Code Playgroud)
起初我预计1200会是某种独特的截止,但在1024(1024产生a mov r0, #1024,而1025使用ldr)和其他值时还有其他截止值.
为什么GCC会使用内存中的负载来获取常量,而不是使用立即数?