这是非常糟糕的微优化,但我只是好奇.它通常不会对"真实"世界产生影响.
所以我正在编译一个函数(什么都不做),compile()然后调用exec该代码并获取对我编译的函数的引用.然后我执行了几百万次计时.然后用本地函数重复它.为什么动态编译的函数只需要调用约15%(在python 2.7.2上)?
import datetime
def getCompiledFunc():
cc = compile("def aa():pass", '<string>', 'exec')
dd = {}
exec cc in dd
return dd.get('aa')
compiledFunc = getCompiledFunc()
def localFunc():pass
def testCall(f):
st = datetime.datetime.now()
for x in xrange(10000000): f()
et = datetime.datetime.now()
return (et-st).total_seconds()
for x in xrange(10):
lt = testCall(localFunc)
ct = testCall(compiledFunc)
print "%s %s %s%% slower" % (lt, ct, int(100.0*(ct-lt)/lt))
Run Code Online (Sandbox Code Playgroud)
我得到的输出是这样的:
1.139 1.319 15% slower
Run Code Online (Sandbox Code Playgroud) 这个问题不是关于C++语言本身(即不是关于标准),而是关于如何调用编译器来实现虚函数的替代方案.
实现虚函数的一般方案是使用指向指针表的指针.
class Base {
private:
int m;
public:
virtual metha();
};
Run Code Online (Sandbox Code Playgroud)
等价地说C会是这样的
struct Base {
void (**vtable)();
int m;
}
Run Code Online (Sandbox Code Playgroud)
第一个成员通常是指向虚拟函数列表等的指针(应用程序无法控制的内存中的一块区域).在大多数情况下,这会在考虑成员之前花费指针的大小等等.因此在大约4个字节的32位寻址方案中等等.如果在应用程序中创建了40k多态对象的列表,则大约为40k x在任何成员变量等之前4个字节= 160k字节.我也知道这恰好是C++编译中最快和最常见的实现.
我知道多重继承很复杂(尤其是虚拟类,即菱形结构等).
另一种方法是将第一个变量作为vptrs表的索引id(等效于C,如下所示)
struct Base {
char classid; // the classid here is an index into an array of vtables
int m;
}
Run Code Online (Sandbox Code Playgroud)
如果应用程序中的类总数小于255(包括所有可能的模板实例化等),则char足以保存索引,从而减少应用程序中所有多态类的大小(我排除了对齐问题)等).
我的问题是,在GNU C++,LLVM或任何其他编译器中是否有任何切换来执行此操作?或减少多态对象的大小?
编辑:我了解指出的对齐问题.还有一点,如果这是64位系统(假设为64位vptr),每个多态对象成员的成本约为8字节,那么vptr的成本就是内存的50%.这主要涉及大量创建的小型多态,所以我想知道如果不是整个应用程序,这个方案是否至少可以用于特定的虚拟对象.
c++ compiler-construction micro-optimization compiler-optimization vptr
我正在尝试在应用程序架构中的非常低级别对我的代码进行微优化.所以这是我的具体情况:
[在描述我可能的解决方案之前,我想解释为什么我在这里进行微优化(你可以跳过这一段):解析器类有很多小方法,其中"小"意味着它们没有做太多.它们中的大多数只从缓存的比特流中读取一个或两个字节,甚至只读取一个比特.所以应该可以以非常有效的方式实现它们,其中函数调用在内联时只需要少量的机器命令.这些方法在应用程序中经常被调用,因为它们在一个非常大的图形(全球道路网络)中查找节点属性,每个用户请求可能会发生大约一百万次,并且这样的请求应该像可能.]
去哪儿路?我可以看到以下方法来解决问题:
有没有更好的方法来解决这个问题?这有什么成语吗?
为了澄清,我有很多与版本无关的函数(至少到现在为止),因此非常适合某些超类.我将对大多数函数使用标准的子类设计,而这个问题仅涵盖要优化的版本相关函数的解决方案.(其中一些不经常被调用,我当然可以在这些情况下使用虚方法.)除此之外,我不喜欢让解析器类决定哪些方法需要高性能而哪些方法无效.(虽然有可能这样做.)
我想在C++中定义一个新类型,它只是一些原始类型(在我的例子中int,可以是任何类型).我NodeId在这个例子中调用了这个类型.
我可以用typedef int NodeId.我想要一个NodeIds 的默认值,所以我会用#define NULL_NODE_ID -1.
现在,我认为定义一个类而不是typedef允许一个函数isValid()和构造一个null的默认构造函数会更好NodeId:
class NodeId
{
int value;
public:
inline NodeId() : value(-1) {}
inline NodeId(int value) : value(value) {}
inline operator int() {return value;}
inline bool isValid() {return value != -1;}
//...
};
Run Code Online (Sandbox Code Playgroud)
是否存在导致使用第二种方法的性能缺点?
如果我将一次迭代变量声明为类成员,我想我会节省一些时间:
struct Foo {
int i;
void method1() {
for(i=0; i<A; ++i) ...
}
void method2() {
for(i=0; i<B; ++i) ...
}
} foo;
Run Code Online (Sandbox Code Playgroud)
然而,这似乎快了20%
struct Foo {
void method1() {
for(int i=0; i<A; ++i) ...
}
void method2() {
for(int i=0; i<B; ++i) ...
}
} foo;
Run Code Online (Sandbox Code Playgroud)
在这段代码中
void loop() { // Arduino loops
foo.method1();
foo.method2();
}
Run Code Online (Sandbox Code Playgroud)
你能解释性能差异吗?
(我需要在Arduino上运行许多简单的paralel"进程",这样的微优化会产生影响.)
在C++中使用int进行x >= 0比较比效率更高x > -1?
我们有一个包含许多实例的类,并遇到内存问题.因此,我们尝试减少这个类的内存需求.一个想法是以下.
该类有许多布尔实例变量,每个变量在初始实现中占用一个单词.可以想到将它们组合到存储在int中的迷你位向量,使得它们的组合存储器要求将是一个字.
但我怀疑Java VM正在进行这种优化,因此手动执行它不会获得任何额外的节省.对?
我知道在C,C++,Java和C#等语言中,(C#示例)else if语句是语法糖,因为它实际上只是一个else语句后跟一个if语句.
else if (conition(s)) { ...
Run Code Online (Sandbox Code Playgroud)
等于
else {
if (condition(s)) { ...
}
Run Code Online (Sandbox Code Playgroud)
但是,在python中,有一个特殊的elif声明.我一直想知道这是否只是开发人员的简写,或者是否有一些隐藏的优化python可以做到这一点,比如更快解释?但这对我来说没有意义,因为其他语言也会这样做(比如JavaScript).所以,我的问题是,在python中,elif语句只是开发人员使用的简写,还是隐藏了它通过这样做而获得的东西?
函数需要大量的堆栈空间是否会阻止它内联?例如,如果我在堆栈上有一个10k自动缓冲区,是否会使该函数不太可能被内联?
int inlineme(int args) {
char svar[10000];
return stringyfunc(args, svar);
}
Run Code Online (Sandbox Code Playgroud)
我更关心gcc,但icc和llvm也很高兴知道.
我知道这不太理想,但我很好奇.缓存上的代码很可能也很糟糕.
我需要以最有效(最快)的方式来弹出大小为128位的无符号变量。
尽管解决方案更便携,甚至更好。
首先,GCC中有两种类型,分别是__uint128_t和unsigned __int128。我猜他们最终还是一样,看不出有什么理由写丑陋的unsigned __int128东西,因此尽管它应该是新类型,但我更喜欢第一个,它与标准更加相似uint64_t。另外,英特尔拥有__uint128_t使用它的另一个原因(可移植性)。
我写了以下代码:
#include <nmmintrin.h>
#include <stdint.h>
static inline uint_fast8_t popcnt_u128 (__uint128_t n)
{
const uint64_t n_hi = n >> 64;
const uint64_t n_lo = n;
const uint_fast8_t cnt_hi = _mm_popcnt_u64(n_hi);
const uint_fast8_t cnt_lo = _mm_popcnt_u64(n_lo);
const uint_fast8_t cnt = cnt_hi + cnt_lo;
return cnt;
}
Run Code Online (Sandbox Code Playgroud)
这是绝对最快的选择吗?
编辑:
我想到了另一个选择,它可能会(或不会)更快:
#include <nmmintrin.h>
#include <stdint.h>
union Uint128 {
__uint128_t …Run Code Online (Sandbox Code Playgroud) c++ ×7
c ×2
gcc ×2
inline ×2
java ×2
optimization ×2
python ×2
abstraction ×1
architecture ×1
bitvector ×1
boolean ×1
dynamic ×1
idioms ×1
if-statement ×1
intel ×1
python-2.7 ×1
vptr ×1
x86-64 ×1