将c实现的静态分配工作空间转换为c ++

时间:2021-05-19 23:13:47

I have a working function implementation in c that requires a large locally allocated chunk of memory as a working space. This function gets called a lot in succession where it is guaranteed that the required amount of working space does not change. To optimize the function I have refactored it to allocate a static single continuous piece of memory the first time it is called, that is only released when it is asked to. It looks something like this

我在c中有一个工作函数实现,它需要一个大的本地分配的内存块作为工作空间。连续调用此函数可确保所需的工作空间量不会发生变化。为了优化函数,我重构了它,以便在第一次调用时分配一个静态的单个连续内存,只有在被要求时才会释放。它看起来像这样

void worker(struct* ptr, size_t m) {
    static double *stack;
    static size_t  sz_stack;
    static double *alpha;
    static double *delta;

    if (!ptr) {
        if (stack) {
            free(stack);
        }
        stack    = NULL;
        sz_stack = 0;
        return;
    }

    if (!stack) {
        sz_stack = 2*m;
        stack    = calloc(sz_stack, sizeof(*stack));

        if (stack==NULL)
            // Error and cleanup
        alpha = stack;
        delta = alpha + m;
    }

    // Do work using alpha and delta as arrays
    return;
}

The caller can call this function successively where ptr will hold the final result as long as the problem size given by m does not change. When the caller is done with the function, or the problem size changes, he calls worker(NULL, 0); and the allocated memory will be freed.

只要m给出的问题大小没有改变,调用者就可以连续调用这个函数,其中ptr将保存最终结果。当调用者完成该函数或问题大小改变时,他调用worker(NULL,0);并释放分配的内存。

I am now working on rewriting this codebase to c++ and as the best practices tell me I have used individual std::vector for alpha and delta instead of the contiguous stack. However, profiling revealed that there is a huge bottleneck as the std::vector containers are allocated and free'd each and every function call.

我现在正在努力将此代码库重写为c ++,并且最佳实践告诉我,我已经使用单独的std :: vector进行alpha和delta而不是连续堆栈。然而,分析显示存在巨大的瓶颈,因为std :: vector容器被分配并释放每个函数调用。

My question now is:

我现在的问题是:

What is the modern c++ way to maintain a contiguous piece of working space for a function in between calls?

什么是在调用之间为函数维护连续工作空间的现代c ++方法?

3 个解决方案

#1


2  

If it is guaranteed that the required working space will not be changing during contiguous function calls (as you mentioned), to me it seems the simplest solution would be to use a static array (somewhat similar to your C code, but using 'new' and 'delete[]' instead of 'calloc' and 'free').

如果保证在连续的函数调用期间所需的工作空间不会改变(如你所提到的),对我来说似乎最简单的解决方案是使用静态数组(有点类似于你的C代码,但使用'new'并'删除[]'而不是'calloc'和'free')。

#2


1  

The C++ way would be to have a class with a private array that you can then manage.

C ++的方法是拥有一个可以管理私有数组的类。

It seems to me that the way you are handling static memory is very analogous to a constructor and destructor. I would have the array as the sole private member and then your worker function as a public member function.

在我看来,处理静态内存的方式非常类似于构造函数和析构函数。我将数组作为唯一的私有成员,然后您的工作者作为公共成员函数。

Also, in terms of performance, STL can do some strange things and each implementation can be more or less strange than the next. If you really want speed (as you've seen), sometimes you have to handle things yourself.

此外,在性能方面,STL可以做一些奇怪的事情,每个实现可能比下一个或多或少奇怪。如果你真的想要速度(如你所见),有时你必须自己处理。

#3


0  

static is a dreadful thing because it plays really badly with thread safety and is wholly unnecessary.

静态是一件可怕的事情,因为它在线程安全方面表现得非常糟糕,完全没必要。

The modern way is one of the following:

现代方式是以下之一:

Declare the memory further up on the stack. vector<> or array<> or even malloc if you like. Pass a pointer (or, equivalently, reference) to this memory into your function.

在堆栈上进一步声明内存。如果你愿意,可以使用vector <>或array <>,甚至是malloc。将指针(或等效地,引用)传递给您的函数。

int main()
{
   vector<double> storage;
   while (1)
   {
      worker(&storage,0,0);
   }
   return 0;
}

Or, write your function as a member of a class. Declare the memory as a member of your class. Create one instance of your class, then call the function repeatedly:

或者,将您的函数编写为类的成员。将内存声明为您的类的成员。创建一个类的实例,然后重复调用该函数:

struct oo_hack
{
  void worker (struct* ptr, size_t m) 
  {
    // Do some things using storage
  }
  vector<double> storage;
}
int main()
{
   oo_hack myhack; // This is on the stack, but has a vector inside
   while (1)
   {
   myhack.worker(0,0);
   }
  return 0;
} // memory gets freed here

I'd suggest declaring the memory further up on the stack and passing it into the functions, but you may prefer the second.

我建议在堆栈中进一步声明内存并将其传递给函数,但您可能更喜欢第二种。

#1


2  

If it is guaranteed that the required working space will not be changing during contiguous function calls (as you mentioned), to me it seems the simplest solution would be to use a static array (somewhat similar to your C code, but using 'new' and 'delete[]' instead of 'calloc' and 'free').

如果保证在连续的函数调用期间所需的工作空间不会改变(如你所提到的),对我来说似乎最简单的解决方案是使用静态数组(有点类似于你的C代码,但使用'new'并'删除[]'而不是'calloc'和'free')。

#2


1  

The C++ way would be to have a class with a private array that you can then manage.

C ++的方法是拥有一个可以管理私有数组的类。

It seems to me that the way you are handling static memory is very analogous to a constructor and destructor. I would have the array as the sole private member and then your worker function as a public member function.

在我看来,处理静态内存的方式非常类似于构造函数和析构函数。我将数组作为唯一的私有成员,然后您的工作者作为公共成员函数。

Also, in terms of performance, STL can do some strange things and each implementation can be more or less strange than the next. If you really want speed (as you've seen), sometimes you have to handle things yourself.

此外,在性能方面,STL可以做一些奇怪的事情,每个实现可能比下一个或多或少奇怪。如果你真的想要速度(如你所见),有时你必须自己处理。

#3


0  

static is a dreadful thing because it plays really badly with thread safety and is wholly unnecessary.

静态是一件可怕的事情,因为它在线程安全方面表现得非常糟糕,完全没必要。

The modern way is one of the following:

现代方式是以下之一:

Declare the memory further up on the stack. vector<> or array<> or even malloc if you like. Pass a pointer (or, equivalently, reference) to this memory into your function.

在堆栈上进一步声明内存。如果你愿意,可以使用vector <>或array <>,甚至是malloc。将指针(或等效地,引用)传递给您的函数。

int main()
{
   vector<double> storage;
   while (1)
   {
      worker(&storage,0,0);
   }
   return 0;
}

Or, write your function as a member of a class. Declare the memory as a member of your class. Create one instance of your class, then call the function repeatedly:

或者,将您的函数编写为类的成员。将内存声明为您的类的成员。创建一个类的实例,然后重复调用该函数:

struct oo_hack
{
  void worker (struct* ptr, size_t m) 
  {
    // Do some things using storage
  }
  vector<double> storage;
}
int main()
{
   oo_hack myhack; // This is on the stack, but has a vector inside
   while (1)
   {
   myhack.worker(0,0);
   }
  return 0;
} // memory gets freed here

I'd suggest declaring the memory further up on the stack and passing it into the functions, but you may prefer the second.

我建议在堆栈中进一步声明内存并将其传递给函数,但您可能更喜欢第二种。