- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在重构我制作的c++ OpenGL应用程序(从技术上讲,该应用程序大量使用了Qt的QQuickItem类中的瘦OpenGL包装器)。我的应用程序运行正常,但可能会更好。
我很好奇的问题之一是在时间敏感型(帧速率)算法中使用virtual
函数。我的OpenGL绘图代码在需要绘图的各种对象上调用了许多virtual
函数。由于这种情况每秒发生多次,因此我想知道virtual
调度是否可以降低帧速率。
我正在考虑更改为这种结构,从而通过将所有内容保留在一个基类中来避免继承,但是以前的virtual
函数现在仅包含switch
语句,以根据该类的“类型”调用适当的例程,而这实际上只是一个typedef enum
:
之前:
struct Base{
virtual void a()=0;
virtual void b()=0;
}
struct One : public Base{
void a(){...}
void b(){...}
}
struct Combined{
MyEnumTypeDef t; //essentially holds what "type" of object this is
void a(){
switch (t){
case One:
....
break;
case Two:
....
break;
}
}
}
a()
函数时,我倾向于认为
Combined
类的效率将大大提高,因为它不需要在虚拟表上进行动态分派(dispatch)。
最佳答案
就您而言,这可能并不重要。我说这可能是因为,并且我有 build 性的意思是,您没有指定性能要求,也没有指定调用该函数的频率,这一事实表明您现在可能没有足够的信息来做出判断-“不要” t推测:“概要”一揽子响应实际上仅旨在确保您拥有所需的所有必要信息,因为过早的微优化非常普遍,我们的真正目标是在全局上帮助您。
杰里米·弗里斯纳(Jeremy Friesner)的his comment on another answer here确实打在了头上:
If you don't understand why it is slow you won't be able to speed it up.
virtual
函数最多可能最终会在某个地方的表中进行一次额外的查找(并且可能会丢失一些高速缓存,但是如果在一个内部循环中重复访问它,则不会那么多),这需要几个CPU时钟。循环最坏的情况(虽然实际上没有实际意义,但最有可能仍小于
switch
),与目标帧速率,渲染帧所需的工作量以及您所使用的任何其他算法和逻辑相比,
完全不重要表演。 如果您想向自己证明,请配置文件。
gcc -O0
编译时的输出,进行1,000,000,000次迭代:
$ g++ -O0 tester.cpp
$ ./a.out
--------------------
Test: time=6.34 sec (switch add) [-358977076]
Test: time=6.44 sec (switch subtract) [358977076]
Test: time=6.96 sec (switch alternating) [-281087476]
Test: time=18.98 sec (switch mixed) [-314721196]
Test: time=6.11 sec (virtual add) [-358977076]
Test: time=6.19 sec (virtual subtract) [358977076]
Test: time=7.88 sec (virtual alternating) [-281087476]
Test: time=19.80 sec (virtual mixed) [-314721196]
Test: time=10.96 sec (ptm add) [-358977076]
Test: time=10.83 sec (ptm subtract) [358977076]
Test: time=12.53 sec (ptm alternating) [-281087476]
Test: time=24.24 sec (ptm mixed) [-314721196]
Test: time=6.94 sec (ptm add (direct)) [-358977076]
Test: time=6.89 sec (ptm subtract (direct)) [358977076]
Test: time=9.12 sec (ptm alternating (direct)) [-281087476]
Test: time=21.19 sec (ptm mixed (direct)) [-314721196]
gcc -O3
编译时的输出,进行1,000,000,000次迭代:
$ g++ -O3 tester.cpp ; ./a.out
--------------------
Test: time=0.87 sec (switch add) [372023620]
Test: time=1.28 sec (switch subtract) [-372023620]
Test: time=1.29 sec (switch alternating) [101645020]
Test: time=7.71 sec (switch mixed) [855607628]
Test: time=2.95 sec (virtual add) [372023620]
Test: time=2.95 sec (virtual subtract) [-372023620]
Test: time=14.74 sec (virtual alternating) [101645020]
Test: time=9.39 sec (virtual mixed) [855607628]
Test: time=4.20 sec (ptm add) [372023620]
Test: time=4.21 sec (ptm subtract) [-372023620]
Test: time=13.11 sec (ptm alternating) [101645020]
Test: time=9.32 sec (ptm mixed) [855607628]
Test: time=3.37 sec (ptm add (direct)) [372023620]
Test: time=3.37 sec (ptm subtract (direct)) [-372023620]
Test: time=13.08 sec (ptm alternating (direct)) [101645020]
Test: time=9.74 sec (ptm mixed (direct)) [855607628]
-O3
发挥了很多作用,并且在不查看汇编程序的情况下,我们不能将其用作当前问题的100%准确表示。
object->*ptm_
)与virtual相似,但要慢于virtual。 object->doit()
,doit()
称为this->*ptm_
)调用成员时指向成员的指针花费的时间不到两倍。 -O0
慢,并且比“mixed”慢。在家里的PC上不会发生这种情况。 ->
与
->*
),因此不能将其直接替换为另一种实现。例如,我不得不创建一整套单独的测试用例来进行处理。
-O3
引入了更多变量,因此结果必须要花点时间,并且不太可能适用于其他情况(换句话说,测试可能很有趣,但并不特别有意义。
// === begin timing ===
#ifdef __linux__
# include <sys/time.h>
typedef struct timeval Time;
static void tick (Time &t) {
gettimeofday(&t, 0);
}
static double delta (const Time &a, const Time &b) {
return
(double)(b.tv_sec - a.tv_sec) +
(double)(b.tv_usec - a.tv_usec) / 1000000.0;
}
#else // windows; untested, working from memory; sorry for compile errors
# include <windows.h>
typedef LARGE_INTEGER Time;
static void tick (Time &t) {
QueryPerformanceCounter(&t);
}
static double delta (const Time &a, const Time &b) {
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
return (double)(b.QuadPart - a.QuadPart) / (double)freq.QuadPart;
}
#endif
// === end timing
#include <cstdio>
#include <cstdlib>
#include <ctime>
using namespace std;
// Size of dataset.
static const size_t DATASET_SIZE = 10000000;
// Repetitions per test.
static const unsigned REPETITIONS = 100;
// Class performs operations with a switch statement.
class OperatorSwitch {
public:
enum Op { Add, Subtract };
explicit OperatorSwitch (Op op) : op_(op) { }
int perform (int a, int b) const {
switch (op_) {
case Add: return a + b;
case Subtract: return a - b;
}
}
private:
Op op_;
};
// Class performs operations with pointer-to-member.
class OperatorPTM {
public:
enum Op { Add, Subtract };
explicit OperatorPTM (Op op) {
perform_ = (op == Add) ?
&OperatorPTM::performAdd :
&OperatorPTM::performSubtract;
}
int perform (int a, int b) const { return (this->*perform_)(a, b); }
int performAdd (int a, int b) const { return a + b; }
int performSubtract (int a, int b) const { return a - b; }
//private:
int (OperatorPTM::*perform_) (int, int) const;
};
// Base class for virtual-function test operator.
class OperatorBase {
public:
virtual ~OperatorBase () { }
virtual int perform (int a, int b) const = 0;
};
// Addition
class OperatorAdd : public OperatorBase {
public:
int perform (int a, int b) const { return a + b; }
};
// Subtraction
class OperatorSubtract : public OperatorBase {
public:
int perform (int a, int b) const { return a - b; }
};
// No base
// Addition
class OperatorAddNoBase {
public:
int perform (int a, int b) const { return a + b; }
};
// Subtraction
class OperatorSubtractNoBase {
public:
int perform (int a, int b) const { return a - b; }
};
// Processes the dataset a number of times, using 'oper'.
template <typename T>
static void test (const int *dataset, const T *oper, const char *name) {
int result = 0;
Time start, stop;
tick(start);
for (unsigned n = 0; n < REPETITIONS; ++ n)
for (size_t i = 0; i < DATASET_SIZE; ++ i)
result = oper->perform(result, dataset[i]);
tick(stop);
// result is computed and printed so optimizations do not discard it.
printf("Test: time=%.2f sec (%s) [%i]\n", delta(start, stop), name, result);
fflush(stdout);
}
// Processes the dataset a number of times, alternating between 'oper[0]'
// and 'oper[1]' per element.
template <typename T>
static void testalt (const int *dataset, const T * const *oper, const char *name) {
int result = 0;
Time start, stop;
tick(start);
for (unsigned n = 0; n < REPETITIONS; ++ n)
for (size_t i = 0; i < DATASET_SIZE; ++ i)
result = oper[i&1]->perform(result, dataset[i]);
tick(stop);
// result is computed and printed so optimizations do not discard it.
printf("Test: time=%.2f sec (%s) [%i]\n", delta(start, stop), name, result);
fflush(stdout);
}
// Processes the dataset a number of times, choosing between 'oper[0]'
// and 'oper[1]' randomly (based on value in dataset).
template <typename T>
static void testmix (const int *dataset, const T * const *oper, const char *name) {
int result = 0;
Time start, stop;
tick(start);
for (unsigned n = 0; n < REPETITIONS; ++ n)
for (size_t i = 0; i < DATASET_SIZE; ++ i) {
int d = dataset[i];
result = oper[d&1]->perform(result, d);
}
tick(stop);
// result is computed and printed so optimizations do not discard it.
printf("Test: time=%.2f sec (%s) [%i]\n", delta(start, stop), name, result);
fflush(stdout);
}
// Same as test() but calls perform_() pointer directly.
static void test_ptm (const int *dataset, const OperatorPTM *oper, const char *name) {
int result = 0;
Time start, stop;
tick(start);
for (unsigned n = 0; n < REPETITIONS; ++ n)
for (size_t i = 0; i < DATASET_SIZE; ++ i)
result = (oper->*(oper->perform_))(result, dataset[i]);
tick(stop);
// result is computed and printed so optimizations do not discard it.
printf("Test: time=%.2f sec (%s) [%i]\n", delta(start, stop), name, result);
fflush(stdout);
}
// Same as testalt() but calls perform_() pointer directly.
static void testalt_ptm (const int *dataset, const OperatorPTM * const *oper, const char *name) {
int result = 0;
Time start, stop;
tick(start);
for (unsigned n = 0; n < REPETITIONS; ++ n)
for (size_t i = 0; i < DATASET_SIZE; ++ i) {
const OperatorPTM *op = oper[i&1];
result = (op->*(op->perform_))(result, dataset[i]);
}
tick(stop);
// result is computed and printed so optimizations do not discard it.
printf("Test: time=%.2f sec (%s) [%i]\n", delta(start, stop), name, result);
fflush(stdout);
}
// Same as testmix() but calls perform_() pointer directly.
static void testmix_ptm (const int *dataset, const OperatorPTM * const *oper, const char *name) {
int result = 0;
Time start, stop;
tick(start);
for (unsigned n = 0; n < REPETITIONS; ++ n)
for (size_t i = 0; i < DATASET_SIZE; ++ i) {
int d = dataset[i];
const OperatorPTM *op = oper[d&1];
result = (op->*(op->perform_))(result, d);
}
tick(stop);
// result is computed and printed so optimizations do not discard it.
printf("Test: time=%.2f sec (%s) [%i]\n", delta(start, stop), name, result);
fflush(stdout);
}
int main () {
int *dataset = new int[DATASET_SIZE];
srand(time(NULL));
for (int n = 0; n < DATASET_SIZE; ++ n)
dataset[n] = rand();
OperatorSwitch *switchAdd = new OperatorSwitch(OperatorSwitch::Add);
OperatorSwitch *switchSub = new OperatorSwitch(OperatorSwitch::Subtract);
OperatorSwitch *switchAlt[2] = { switchAdd, switchSub };
OperatorBase *virtAdd = new OperatorAdd();
OperatorBase *virtSub = new OperatorSubtract();
OperatorBase *virtAlt[2] = { virtAdd, virtSub };
OperatorPTM *ptmAdd = new OperatorPTM(OperatorPTM::Add);
OperatorPTM *ptmSub = new OperatorPTM(OperatorPTM::Subtract);
OperatorPTM *ptmAlt[2] = { ptmAdd, ptmSub };
while (true) {
printf("--------------------\n");
test(dataset, switchAdd, "switch add");
test(dataset, switchSub, "switch subtract");
testalt(dataset, switchAlt, "switch alternating");
testmix(dataset, switchAlt, "switch mixed");
test(dataset, virtAdd, "virtual add");
test(dataset, virtSub, "virtual subtract");
testalt(dataset, virtAlt, "virtual alternating");
testmix(dataset, virtAlt, "virtual mixed");
test(dataset, ptmAdd, "ptm add");
test(dataset, ptmSub, "ptm subtract");
testalt(dataset, ptmAlt, "ptm alternating");
testmix(dataset, ptmAlt, "ptm mixed");
test_ptm(dataset, ptmAdd, "ptm add (direct)");
test_ptm(dataset, ptmSub, "ptm subtract (direct)");
testalt_ptm(dataset, ptmAlt, "ptm alternating (direct)");
testmix_ptm(dataset, ptmAlt, "ptm mixed (direct)");
}
}
关于c++ - 虚函数性能: one large class vs many smaller subclasses,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22975959/
matplotlibrc 示例文件指出: ## The font.size property is the default font size for text, given in pts. ## 1
在 HTML/CSS 中,可以通过以下方式指定字体大小(已弃用,但所有浏览器都支持): text n 是 {1, 2, 3, 4, 5, 6, 7} 的一个元素。 另一种可能性是: text s 是
我正在编写物理模拟代码,最近我遇到了异常结果。我设法调试了我的程序,错误出在用大整数除以大 double ,形式如下: cout << my_large_double/my_large_int <<
由于“大”是一个相对术语,我想知道“大”的确切含义是什么。更具体地说,我想在数据库中存储从几个字节到 50 个字节的二进制数据,并且想知道是否应该使用 Blob 或其他数据类型。 最佳答案 所有 DB
这是我的代码的想法: 我有一个很大的电子邮件数据 RDD,称为 email。大约 7 亿封电子邮件。它看起来像这样: [['value1','value2','value3','value4'],['
我需要拆分由另一个 Pig 脚本生成的输出部分文件,并生成每个包含 1000 行的组。这些组将发布到网络服务以供进一步处理。数据之间没有关系,所以我无法将数据分组到特定字段。 我如何在 Pig 中执行
它们都有 2vcpu 和 8G 内存。但对于 t2.large,您只能使用单个 vcpu 的 60%,两个 vcpu 平均各使用 30%。即使考虑到“CPU积分”,t2.large似乎也比m4.lar
我正在尝试使用 git svn 克隆一个大型 svn 存储库。 repo 有 100000 次修订。大小约为 9GB(原始文件夹)。 repo 协议(protocol)中的最大文件是 300 MB。
我刚接触 android。在我的教程书中(有点过时)在Eclipse中教学,只是在layout-large目录下编写另一个layout xml文件以适配大屏。 我使用的是android studio,
如果我要升级亚马逊实例,我会创建镜像的快照并从该镜像创建新实例,然后升级该实例。 我的问题与 mongodb 以及从 m1.large 升级到 m3.large 实例的最佳方式有关 - 基本上 m3
这个问题可能需要一些编译器知识才能回答。我目前正在做一个项目,我将在其中创建一个数组,可能是 int[2][veryLargeNumber] 或 int [veryLargeNumber][2] 逻辑
我在使用 mysql 5.5.12 时遇到了 Amazon RDS 的 IO 性能问题。有 2 种实例类型相似且价格接近: 超大数据库实例:15 GB 内存、8 个 ECU(4 个虚拟核心,每个 2
我需要设计一个包含大量字段的网页,每个字段都显示在一行表格中。有几个类别。我希望为每个类别制作一个单独的表格并进行不同的设计。 网页上存在大量表格是否会使速度变慢?哪个更好.. 有 10 个表,每个表
我在my.cnf中添加了如下内容 [mysqld] max_allowed_packet=32M [mysql] max_allowed_packet=32M 而且我还在 JDBC 查询中添加了以下内
我正在为 Nexus 4、Samsung 7.7、Nexus 7、S3 和 Note-2 开发应用程序。我正在为所有这些布局制作一个 apk。除 Nexus 7 和 Samsung 7.7 外,其他一
我有一个包含大约 1000 万行且大小约为 400mb 的文件,我的系统无法处理它。当我尝试使用 gedit 打开文件时,它卡住了。有没有办法处理这么大的数据文件。 最佳答案 使用 gnu(Windo
这个问题已经有答案了: "Integer too large" for a small compile time constant (4 个回答) 已关闭 6 年前。 当我添加整数时,即使我将其加倍,
这个问题已经有答案了: "Integer number too large" error message for 600851475143 (8 个回答) Java long number too l
我们正在开发一个注册系统,但现在由于编译期间出现内存错误而陷入困境。 我们上网查了一下,发现错误信息的原因是.java文件的大小。我们的 EnrollmentSystem 类现在有 10171 行代码
这个问题已经有答案了: How to import large sql file in phpmyadmin (23 个回答) 已关闭 4 年前。 我刚刚在 Digital Ocean 上设置了一个
我是一名优秀的程序员,十分优秀!