C++ 堆解决方案优于堆栈?

C++ 堆解决方案优于堆栈?,c++,c,C++,C,我正在编写一个C模拟,在这个模拟中,给定一系列要验证的规则,我们将其分解为“切片”,并验证每个切片。(基本思想是顺序很重要,规则的实际含义受其上面的一些规则的影响;我们可以用每个规则和上面重叠的规则制作一个“切片”。然后我们验证切片,这些切片通常比整个序列小得多。) 我的问题如下 我有一个结构(策略),它包含一个结构(规则)数组和一个int(长度)。 我最初的实现大量使用malloc和realloc: struct{ struct rule *rules; int length; }po

我正在编写一个C模拟,在这个模拟中,给定一系列要验证的规则,我们将其分解为“切片”,并验证每个切片。(基本思想是顺序很重要,规则的实际含义受其上面的一些规则的影响;我们可以用每个规则和上面重叠的规则制作一个“切片”。然后我们验证切片,这些切片通常比整个序列小得多。)

我的问题如下

我有一个结构(策略),它包含一个结构(规则)数组和一个int(长度)。 我最初的实现大量使用malloc和realloc:

struct{
  struct rule *rules;
  int length;
}policy;
...
struct policy makePolicy(int length)
{
  struct policy newPolicy;
  newPolicy.rules = malloc(length * sizeof(struct rule));
  newPolicy.length = length;
  return newPolicy;
}
...
struct policy makeSlice(struct policy inPol, int rulePos)
{
  if(rulePos > inPol.length - 1){
    printf("Slice base outside policy \n");
    exit(1);
   }
  struct slice = makePolicy(inPol.length);
  //create slice, loop counter gets stored in sliceLength
  slice.rules = realloc(slice.rules, sliceLength * sizeof(struct rule));
  slice.length = sliceLength;
  return slice;
}
由于它使用malloc'ed内存,我假设它大量使用堆。 现在我正在尝试移植到一个实验性的并行机,它没有malloc

我很伤心地去分配所有固定大小的数组

现在令人震惊的是

新代码运行速度较慢。慢多了

(最初的代码在片长为200时会连续等待几分钟,在超过300时可能会等待一个小时……现在,当片长为70、80时会等待几分钟,而在片长为120时则会等待几小时。现在仍然不是200。)

唯一的问题是,现在这些片被赋予了与完整策略相同的内存(MAXBUFLEN是10000),但整个片似乎根本没有耗尽内存top'显示,与以前一样,消耗的总内存非常适中,范围为数十兆字节。(当然,当我存储长度时,我并不是在整个过程中循环,只是有真正规则的部分。)


有人能解释一下为什么它突然变得这么慢吗?

似乎当你将结构的大小固定到一个更大的大小(比如10000条规则)时,你的缓存位置可能会比原来的更差。您可以使用探查器(oprofile或Valgrind中的cachegrind)查看缓存是否存在问题

在原始程序中,一条缓存线最多可以容纳8个结构策略(在具有64字节缓存线的32位计算机上)。但在修改后的verison中,它只能容纳一个,因为它现在比缓存线大得多

在这种情况下,向上移动
length
字段可以提高性能,因为现在
length
和前几个
struct规则可以放入单个缓存线

struct policy{
  int length;
  struct rule rules[10000];
};

要解决这个问题,您需要编写自己的自定义分配器以确保缓存位置。如果您正在编写此程序的并行版本,还请记住将不同线程使用的内存隔离到不同的缓存线中,以避免缓存线争用。

是否尝试使用探查器?它在新机器上运行得慢还是在同一台机器上运行得慢?你是说它现在在同一台机器上运行得慢?或者它在你的“实验性并行”机器上运行较慢?到目前为止,这是在同一台机器上。我还没有在平行机上运行它。我应该补充一下,验证是order pow(n,5),其中n是规则数。因此,我认为核查需要时间。我现在正在尝试学习gprof,这样我可以更好地分析和回答这个问题。分析代码的一个简单(有效)方法就是以几个随机间隔从中获取堆栈跟踪,可以使用gstack或gdb。您只需要几个示例就可以确定大部分执行时间都花在了什么地方。为什么您的
realloc
调用中只有一个arg?感谢您提出的字段移动想法,但恐怕到目前为止还没有太大区别。我已经实现了顺序切换,但是一个带有50-75条规则的片段在旧版本中闪烁,现在仍然在屏幕上停留了几分钟。我将尝试看看Valgrind,但我非常希望能有一些关于如何编写自己的分配器的建议,以及如何隔离每个线程的内存@user2431187似乎除了缓存问题可能导致的性能差异之外,还存在其他性能差异。除了数据结构之外,您是否对程序进行了其他更改?代码的唯一其他更改是,我还在probe()函数中使用了固定长度数组来保存测试数据点。(这是一个相当大的数组,但仍然不超过1兆字节左右。)作为测试,我再次返回并编辑了代码,使用malloc()作为数据点数组。在我的测试中,这段代码的运行速度比只使用静态数组的代码快,但没有malloc()贯穿其中的代码快。(假设一个最大片段长度为130的示例,动态代码需要半个多小时,而静态代码则需要一整晚。)@user2431187您正在编写并行程序吗?如果是这样,您必须使用线程本地数组而不是全局数组来避免错误共享。最终目标是获得一个并行程序,但到目前为止我还没有转换它。事实上,第一个障碍是rand()、time()和malloc()在新机器上不可用。我将编写自己的rand()并从命令行传入种子,而不是time(),但我还想弄清楚为什么离开malloc()会让它变得如此缓慢:)并且没有全局数组,probe()是一个函数,每个线程只调用一次,它将策略作为输入,生成一个测试点数组,并用这些观点来检验政策。该数组是probe()的本地数组,不是共享数组。