我有以下功能:
double
neville (double xx, size_t n, const double *x, const double *y, double *work);
使用xx
和n
中存储的x
点在y
执行拉格朗日插值。 work
数组的大小为2 * n
。由于这是多项式插值,n
在大约5的范围内,很少超过10。
此功能经过积极优化,应该在紧密循环中调用。分析表明在循环中分配工作数组的堆很糟糕。不幸的是,我应该把它打包成一个类似函数的类,客户端必须不知道工作数组。
目前,我使用模板整数参数作为度和std::array
以避免动态分配work
数组:
template <size_t n>
struct interpolator
{
double operator() (double xx) const
{
std::array<double, 2 * n> work;
size_t i = locate (xx); // not shown here, no performance impact
// due to clever tricks + nice calling patterns
return neville (xx, n, x + i, y + i, work.data ());
}
const double *x, *y;
};
将工作数组存储为类的可变成员是可能的,但operator()
应该由多个线程同时使用。如果您在编译时知道n
,则此版本可以。
现在,我需要在运行时指定n
参数。我想知道这样的事情:
double operator() (double xx) const
{
auto work = static_cast<double*> (alloca (n * sizeof (double)));
...
使用alloca
时有些铃声响起:我当然会在n
上设置上限以避免alloca
调用溢出(无论如何,使用100度是非常愚蠢的多项式插值)。
alloca
的明显危险?答案 0 :(得分:5)
然而,我对这种方法很不满意:
- 我错过了一些明显的alloca危险吗?
你指出了一个真正的危险:alloca
未定义堆栈溢出行为。此外,alloca
实际上并未标准化。例如,Visual C ++代替_alloca
和GCC by default defines it as a macro。但是,通过在现有的几个实现中提供一个薄的包装器,可以相当容易地规避这个问题。
- 这里有更好的方法来避免堆分配吗?
不是真的。 C ++ 14将有一个(可能!)堆栈分配的可变长度数组类型。但是在那之前,当你认为std::array
不适合时,请在你的情况下使用alloca
。
虽然有点挑剔:您的代码缺少返回值alloca
的强制转换。它甚至不应该编译。
答案 1 :(得分:2)
总有很多笔记要添加到堆栈内存的任何使用中。正如您所指出的,当空间耗尽时,堆栈具有有限的大小和相当严重的错误行为。如果有防护页面,堆栈溢出肯定会崩溃,但在某些平台和线程环境有时可能是静默损坏(坏)或安全问题(更糟)。
还要记住,与malloc
相比,堆栈分配非常快,(它只是从堆栈指针寄存器中减去)。但该内存的使用可能不是。将堆栈帧大幅下降的副作用是您要调用的叶函数的缓存行不再驻留。因此,任何对该内存的使用都需要转到SMP环境,以使高速缓存行恢复到独占(在MESI意义上)状态。 SMP总线比L1缓存更受约束(!)环境,如果你在垃圾邮件堆栈框架周围这可能是一个真正的可扩展性问题。
另外,就语法而言,请注意gcc和clang(以及我认为的Intel编译器)都支持C99可变长度数组语法作为C ++扩展。您可能根本不需要实际调用libc alloca()
例程。
最后,请注意malloc
真的不那么慢。如果你正在处理数十千字节或更大领域的单个缓冲区,那么为你将要做的任何工作所需的内存带宽将会淹没malloc
的任何开销。
基本上:alloca()
很可爱,并且有其用途,但除非您准备好基准测试证明您需要它,否则您可能不会并且应该坚持使用传统分配。
答案 2 :(得分:1)
这个怎么样:
double operator() (double xx) const
{
double work_static[STATIC_N_MAX];
double* work = work_static;
std::vector<double> work_dynamic;
if ( n > STATIC_N_MAX ) {
work_dynamic.resize(n);
work = &work_dynamic[0];
}
///...
当n
太大时,没有非便携式功能,异常安全,并且会优雅地降级。当然,您可以将work_static
设为std::array
,但我不确定您在此中看到了什么好处。