6

我正在测试一种分子动力学算法,其中包括一个由9 个双精度数组组成的粒子类,用于存储粒子分量(3D 环境中的速度、力和位置)。

我使用 5 个输入大小测试算法:

Size (MB) Time (s)
0.06      0.36     (fits in cache L2)
0.14      1.79     (fits in cache L2)
0.60      36.86    (fits in cache L3)
1.35      182.24   (fits in cache L3)
17.38     566.55   (it only fits in RAM)

比我将Particles布局从更改arrayArrayList. 为了有一个连续的内存块,我创建了 arrayList,其大小将占用:

ArrayList <Double> px = new ArrayList <Double>(Input_Size);

我在上述睾丸的相同条件下运行该版本,结果是:

Size (MB) Time (s)
0.06      0.608
0.14      2.78
0.60      57.15
1.35      299.24
17.38     1436,42

测试环境为:

AMD Opteron 处理器 6174,800 MHz,12 MB Cache L3,24 核;

我的速度降低了大约 2 倍。这是正常的吗?不应该期望在两个版本中几乎相同的时间,因为ArrayList像数组一样在内存中连续分配?

编辑:

Running with the option **-XX:+PrintCompilation**

  WITH ARRAY:

 1       java.util.jar.Manifest$FastInputStream::readLine (167 bytes)
  2       sun.nio.cs.UTF_8$Decoder::decodeArrayLoop (553 bytes)
  3       java.lang.String::hashCode (60 bytes)
  4       java.lang.String::charAt (33 bytes)
  5       sun.security.util.ManifestDigester::findSection (180 bytes)
  6       java.lang.Object::<init> (1 bytes)
  7       moldyn.random::update (104 bytes)
  8       moldyn.random::seed (80 bytes)
---   n   java.lang.StrictMath::log (static)
  9       java.lang.Math::log (5 bytes)
 10       moldyn.md::scalingVelocity (82 bytes)
 11       moldyn.Particles::distance (192 bytes)
  1%      moldyn.Particles::force @ 42 (211 bytes)
 12       moldyn.Particles::force (211 bytes)
 13       moldyn.Particles::domove (163 bytes)
 14       moldyn.Particles::domove_out (160 bytes)
  2%      moldyn.Particles::cicle_domove @ 5 (23 bytes)
 15       moldyn.Particles::update_force (49 bytes)
  3%      moldyn.Particles::cicle_forces @ 6 (27 bytes)
 16       moldyn.Particles::mkekin (141 bytes)
  4%      moldyn.Particles::cicle_mkekin @ 9 (33 bytes)
 17       moldyn.Particles::velavg (70 bytes)
  5%      moldyn.Particles::cicle_velavg @ 9 (37 bytes)
 18       moldyn.Particles::cicle_domove (23 bytes)
 19       moldyn.Particles::cicle_forces (27 bytes)
 20       moldyn.Particles::cicle_mkekin (33 bytes)
 21       moldyn.Particles::cicle_velavg (37 bytes)
36.763

WITH ArrayList <Double>....
----

  1       java.util.jar.Manifest$FastInputStream::readLine (167 bytes)
  2       sun.nio.cs.UTF_8$Decoder::decodeArrayLoop (553 bytes)
  3       java.lang.String::hashCode (60 bytes)
  4       java.lang.String::charAt (33 bytes)
  5       sun.security.util.ManifestDigester::findSection (180 bytes)
  6       java.lang.Object::<init> (1 bytes)
---   n   java.lang.System::arraycopy (static)
  7       java.lang.Number::<init> (5 bytes)
  8       java.util.ArrayList::ensureCapacity (58 bytes)
  9       java.lang.Double::valueOf (9 bytes)
 10       java.lang.Double::<init> (10 bytes)
 11       java.util.ArrayList::add (100 bytes)
 12       java.util.ArrayList::RangeCheck (48 bytes)
 13       java.util.ArrayList::set (21 bytes)
 14       moldyn.random::update (104 bytes)
 15       moldyn.random::seed (80 bytes)
---   n   java.lang.StrictMath::log (static)
 16       java.lang.Math::log (5 bytes)
 17       java.util.ArrayList::get (12 bytes)
 18       java.lang.Double::doubleValue (5 bytes)
 19       moldyn.md::scalingVelocity (120 bytes)
 20       moldyn.Particles::distance (240 bytes)
  1%      moldyn.Particles::force @ 42 (211 bytes)
 21       moldyn.Particles::force (211 bytes)
 22       moldyn.Particles::domove (337 bytes)
 23       moldyn.Particles::domove_out (292 bytes)
  2%      moldyn.Particles::cicle_domove @ 5 (23 bytes)
 24       moldyn.Particles::update_force (91 bytes)
  3%      moldyn.Particles::cicle_forces @ 6 (27 bytes)
 25       moldyn.Particles::mkekin (297 bytes)
  4%      moldyn.Particles::cicle_mkekin @ 9 (33 bytes)
 26       moldyn.Particles::velavg (118 bytes)
  5%      moldyn.Particles::cicle_velavg @ 9 (37 bytes)
 27       moldyn.Particles::cicle_domove (23 bytes)
 28       moldyn.Particles::cicle_forces (27 bytes)
 29       moldyn.Particles::cicle_mkekin (33 bytes)
 30       moldyn.Particles::cicle_velavg (37 bytes)
55.98
4

3 回答 3

6

我有一些想法,但没有明确的答案:

  1. Ajava.lang.Doubledouble原语不同。可能是自动装箱开销和与Double对象一起出现的额外机械有所不同。我会比较字节码,看看是否属实。
  2. 这听起来像是对班级内的客户隐藏double []List<Double>隐藏的选择。Particle如果是这种情况,请使用数组,因为它是内部实现细节。
  3. 我会小心用基准测试欺骗自己。
  4. 我想知道您的Particle课程是否是可变的。那可能会有所作为。位置、速度和力是否不断变化并在您的对象中得到更新?
于 2012-11-25T18:26:01.900 回答
2

我看到 2 个潜在问题:

1:数组周围对象的开销...

ArrayList 在 Array 中存储可变数量的对象。这类似于创建对象数组,但是使用 ArrayList,可以使用公开的方法轻松地从 ArrayList 添加和删除项目,并且可以动态调整其大小。

这可能非常方便,但它比使用许多元素时创建对象数组要慢。

如果您需要功能有限的非常灵活的 Array 类型的集合,ArrayList 可能是一个不错的选择。但是,如果您追求速度,则阵列将获胜。为避免内部重新复制 ArrayList 中的数组,您可以使用

ensureCapacity(int requestCapacity) 

2:在你的具体情况下,可能还会有很多装箱/拆箱来回进行doubleDouble这也会给你一些延迟。

于 2012-11-25T18:23:36.923 回答
1

我建议不要在这个用例中使用数组或 ArrayList。您对此有一个非常明显的面向对象的解决方案,该解决方案被忽略以支持数组。

您应该使用组合来构建更好的结构化程序,它应该更易于阅读并且(可能)不会导致任何额外的开销。

例如。

import javax.vecmath.Vector3d;

public class Particle {

    private Vector3d velocity;
    private Vector3d force; // acceleration?
    private Vector3d position; 

    ...

}

这样您就不必担心边界检查(如数组和 ArrayList 的情况),也不必担心自动装箱(如 ArrayLists 的情况)。您还可以获得粒子速度、加速度和位置的每个值都被恰当命名的好处。也就是说,谁知道particle.getData()[7]指的是什么,而用particle.getPosition().y它是很明显的。最后,Vector3d附带一些可能有用的内置功能。

于 2012-11-25T20:06:14.560 回答