Question:

Editor's clarification: When this was originally posted, there were two issues:

  • Test performance drops by a factor of three if seemingly inconsequential statement added
  • Time taken to complete the test appears to vary randomly

The second issue has been solved: the randomness only occurs when running under the debugger.

The remainder of this question should be understood as being about the first bullet point above, and in the context of running in VC++ 2010 Express's Release Mode with optimizations "Maximize Speed" and "favor fast code".

There are still some Comments in the comment section talking about the second point but they can now be disregarded.


I have a simulation where if I add a simple if statement into the while loop that runs the actual simulation, the performance drops about a factor of three (and I run a lot of calculations in the while loop, n-body gravity for the solar system besides other
things) even though the if statement is almost never executed:

if (time - cb_last_orbital_update > 5000000)
{
cb_last_orbital_update = time;
}

with time and cb_last_orbital_update being both of type
double and defined in the beginning of the main function, where this if statement is too. Usually there are computations I want to run there too, but it makes no difference if I delete them. The if statement as it is above has the same effect on
the performance.

The variable time is the simulation time, it increases in 0.001 steps in the beginning so it takes a really long time until the if statement is executed for the first time (I also included printing a message to see if it is being executed, but
it is not, or at least only when it's supposed to). Regardless, the performance drops by a factor of 3 even in the first minutes of the simulation when it hasn't been executed once yet. If I comment out the line

cb_last_orbital_update = time;

then it runs faster again, so it's not the check for

time - cb_last_orbital_update > 5000000

either, it's definitely the simple act of writing current simulation time into this variable.

Also, if I write the current time into another variable instead of cb_last_orbital_update, the performance does not drop. So this might be an issue with assigning a new value to a variable that is used to check if the "if" should be executed?
These are all shots in the dark though.

Disclaimer: I am pretty new to programming, and sorry for all that text.

I am using Visual C++ 2010 Express, deactivating the stdafx.h precompiled header function didn't make a difference either.

EDIT: Basic structure of the program. Note that nowhere besides at the end of the while loop (time += time_interval;) is
time changed. Also, cb_last_orbital_update has only 3 occurrences: Declaration / initialization, plus the two times in the if statement that is causing the problem.

int main(void)
{
...
double time = 0;
double time_interval = 0.001;
double cb_last_orbital_update = 0; F_Rocket_Preset(time, time_interval, ...); while(conditions)
{
Rocket[active].Stage[Rocket[active].r_stage].F_Update_Stage_Performance(time, time_interval, ...);
Rocket[active].F_Calculate_Aerodynamic_Variables(time);
Rocket[active].F_Calculate_Gravitational_Forces(cb_mu, cb_pos_d, time);
Rocket[active].F_Update_Rotation(time, time_interval, ...);
Rocket[active].F_Update_Position_Velocity(time_interval, time, ...);
Rocket[active].F_Calculate_Orbital_Elements(cb_mu);
F_Update_Celestial_Bodies(time, time_interval, ...); if (time - cb_last_orbital_update > 5000000.0)
{
cb_last_orbital_update = time;
} Rocket[active].F_Check_Apoapsis(time, time_interval);
Rocket[active].F_Status_Check(time, ...);
Rocket[active].F_Update_Mass (time_interval, time);
Rocket[active].F_Staging_Check (time, time_interval); time += time_interval; if (time > 3.1536E8)
{
std::cout << "\n\nBreak main loop! Sim Time: " << time << std::endl;
break;
}
}
...
}

EDIT 2:

Here is the difference in the assembly code. On the left is the fast code with the line

cb_last_orbital_update = time;

outcommented, on the right the slow code with the line.

EDIT 4:

So, i found a workaround that seems to work just fine so far:

int cb_orbit_update_counter = 1; // before while loop

if(time - cb_orbit_update_counter * 5E6 > 0)
{
cb_orbit_update_counter++;
}

EDIT 5:

While that workaround does work, it only works in combination with using
__declspec(noinline)
. I just removed those from the function declarations again to see if that changes anything, and it does.

EDIT 6: Sorry this is getting confusing. I tracked down the culprit for the lower performance when removing
__declspec(noinline) to this function, that is being executed inside the
if:

__declspec(noinline) std::string F_Get_Body_Name(int r_body)
{
switch (r_body)
{
case 0:
{
return ("the Sun");
}
case 1:
{
return ("Mercury");
}
case 2:
{
return ("Venus");
}
case 3:
{
return ("Earth");
}
case 4:
{
return ("Mars");
}
case 5:
{
return ("Jupiter");
}
case 6:
{
return ("Saturn");
}
case 7:
{
return ("Uranus");
}
case 8:
{
return ("Neptune");
}
case 9:
{
return ("Pluto");
}
case 10:
{
return ("Ceres");
}
case 11:
{
return ("the Moon");
}
default:
{
return ("unnamed body");
}
} }

The if also now does more than just increase the counter:

if(time - cb_orbit_update_counter * 1E7 > 0)
{
F_Update_Orbital_Elements_Of_Celestial_Bodies(args);
std::cout << F_Get_Body_Name(3) << " SMA: " << cb_sma[3] << "\tPos Earth: " << cb_pos_d[3][0] << " / " << cb_pos_d[3][1] << " / " << cb_pos_d[3][2] <<
"\tAlt: " << sqrt(pow(cb_pos_d[3][0] - cb_pos_d[0][0],2) + pow(cb_pos_d[3][1] - cb_pos_d[0][1],2) + pow(cb_pos_d[3][2] - cb_pos_d[0][2],2)) << std::endl;
std::cout << "Time: " << time << "\tcb_o_h[3]: " << cb_o_h[3] << std::endl;
cb_orbit_update_counter++;
}

I remove __declspec(noinline) from the function F_Get_Body_Name alone, the code gets slower. Similarly, if i remove the execution of this function or add
__declspec(noinline) again, the code runs faster. All other functions still have
__declspec(noinline).

EDIT 7:So i changed the switch function to

const std::string cb_names[] = {"the Sun","Mercury","Venus","Earth","Mars","Jupiter","Saturn","Uranus","Neptune","Pluto","Ceres","the Moon","unnamed body"}; // global definition
const int cb_number = 12; // global definition std::string F_Get_Body_Name(int r_body)
{
if (r_body >= 0 && r_body < cb_number)
{
return (cb_names[r_body]);
}
else
{
return (cb_names[cb_number]);
}
}

and also made another part of the code slimmer. The program now runs fast without any
__declspec(noinline). As ElderBug suggested, an issue with the CPU instruction cache then / the code getting too big?

Answer:

I'd put my money on Intel's branch predictor. http://en.wikipedia.org/wiki/Branch_predictor

The processor assumes (time - cb_last_orbital_update > 5000000) to be false most of the time and loads up the execution pipeline accordingly.

Once the condition (time - cb_last_orbital_update > 5000000) comes true. The misprediction delay is hitting you. You may loose 10 to 20 cycles.

if (time - cb_last_orbital_update > 5000000)
{
cb_last_orbital_update = time;
}

Rarely executed and almost empty if statement drastically reduces performance in C++的更多相关文章

  1. Following a Select Statement Through Postgres Internals

    This is the third of a series of posts based on a presentation I did at the Barcelona Ruby Conferenc ...

  2. 对PostgreSQL的prepared statement的深入理解

    看官方文档: http://www.postgresql.org/docs/current/static/sql-prepare.html PREPARE creates a prepared sta ...

  3. verilog behavioral modeling--branch statement

    conditional statement case statement 1. conditional statement     if(expression)         statement_o ...

  4. MySQL 5.6 Reference Manual-14.6 InnoDB Table Management

    14.6 InnoDB Table Management 14.6.1 Creating InnoDB Tables 14.6.2 Moving or Copying InnoDB Tables to ...

  5. Introduction to ASP.NET Web Programming Using the Razor Syntax (C#)

    1, http://www.asp.net/web-pages/overview/getting-started/introducing-razor-syntax-c 2, Introduction ...

  6. CoreCLR源码探索(八) JIT的工作原理(详解篇)

    在上一篇我们对CoreCLR中的JIT有了一个基础的了解, 这一篇我们将更详细分析JIT的实现. JIT的实现代码主要在https://github.com/dotnet/coreclr/tree/m ...

  7. Practical Go: Real world advice for writing maintainable Go programs

    转自:https://dave.cheney.net/practical-go/presentations/qcon-china.html?from=timeline   1. Guiding pri ...

  8. SAP NOTE 1999997 - FAQ: SAP HANA Memory

    Symptom You have questions related to the SAP HANA memory. You experience a high memory utilization ...

  9. 【ruby】ruby基础知识

    Install Ruby(安装) For windows you can download Ruby from http://rubyforge.org/frs/?group_id=167 for L ...

随机推荐

  1. [solution] JZOJ-5795 词典

    [solution]JZOJ-5795 词典 题面 Description 小C有$n$个字符串$T_1 T_n$,给出$m$个询问 第$i$个询问给出一个字符串$S_i$,对于每个询问,我们可以得到 ...

  2. 【pycharm 密钥】pycharm 2017 密钥

    server选项里边输入:  http://idea.liyang.io   亲测可用!!!

  3. 多态&虚函数

     (1).对象类型:           a.静态类型:对象声明时的类型,编译的时候确定           b.动态类型:对象的类型是运行时才能确定的 class A {}; class B:pub ...

  4. day_1 Python介绍及计算机组成和系统

    python学习路线 基础语法 - 文件操作 - 函数 - 模块 - 面向对象(类) - 网络编程 - 数据库 - 前段 - 项目 学习方法 wwwh: what-why-where-how #wha ...

  5. ReactNative学习笔记(一)环境搭建

    前言 本文开发环境为Windows,目标平台为Android,react-native版本为0.35.0. 环境搭建 注意,本文不是按照官网的教程来的,官网说必须安装什么Chocolatey,我懒得鸟 ...

  6. 在Git中设置自己的姓名

    在Git中,自己的姓名与每一个commit提交绑定在一起.如果你在使用Azure DevOps Server中的Git Repo时,一定要注意commit中的提交者与服务器上的推送者,是两个概念. 在 ...

  7. DLL补丁劫持制作

    DLL: 由于输入表中只包含 DLL 名而没有它的路径名,因此加载程序必须在磁盘上搜索 DLL 文件.首先会尝试从当前程序所在的目录加载 DLL,如果没找到,则在Windows 系统目录中查找,最后是 ...

  8. 使用onpaste粘贴事件引起的探索

    前天项目有一个需求,在Excel文档里面直接复制商品编码,然后粘贴到页面空白处就把相应的数据加载出来.当时我是懵逼的,不知道如何下手. 以前没遇到过类似的需求,后来才想起onpaste事件 在使用on ...

  9. jdk的安装和配置环境变量

    一.下载 JDK是个免费的东东,所以大家不要去百度啥破解版了,直接去官网下载最新版本吧,比较安全,官网地址:http://www.oracle.com/technetwork/java/index.h ...

  10. [NOIP模拟赛] 序列

    Description 给定一个1~n的排列x,每次你可以将x1~xi翻转.你需要求出将序列变为升序的最小操作次数.有多组数据. Input 第一行一个整数t表示数据组数. 每组数据第一行一个整数n, ...