Continuando a pergunta de ontem: std::priority_queue pre-allocate memory erro de memória
Estou trabalhando em um projeto determinÃstico em tempo real que tem um ciclo de execução por iteração de algumas centenas de microssegundos.
Estou enfrentando um problema em que a operação push em um std::queue e std::priority_queue aleatoriamente está levando muito tempo. A operação push geralmente leva cerca de 5 a 25 microssegundos, mas aleatoriamente leva de 300 microssegundos a 5 milissegundos.
Para superar esse problema, decidi pré-alocar memória para meu std::queue e std::priority_queue.
Estou me referindo à seguinte resposta: https://stackoverflow.com/a/79433983/6319901
SO de desenvolvimento: Ubuntu 24.04 LTS.
Meu SO de destino: vxWorks 7
Linguagem: C++17
Código:
#include <queue>
#include <array>
#include <vector>
#include <string>
#include <cstdint>
#include <iostream>
#include <functional>
static const std::size_t MAX_PACKET_LENGTH = 512;
struct receive_t
{
int data1;
float data2;
std::string data;
receive_t()
{
data.reserve(MAX_PACKET_LENGTH);
}
};
int main(int argc, char const *argv[])
{
std::cout << "Hello, World!!!\n";
std::vector<receive_t> container;
container.reserve(1000);
std::queue<receive_t,
std::vector<receive_t>> q
(
std::move(container)
);
std::cout << "sizeof(receive_t) : " << sizeof(receive_t) << std::endl;
std::cout << "sizeof(q) : " << sizeof(q) << std::endl;
std::cout << "q.size() : " << q.size() << std::endl;
return 0;
}
SaÃda:
Hello, World!!!
sizeof(receive_t) : 40
sizeof(q) : 24
q.size() : 0
Tenho 2 perguntas:
- Como verifico a memória total alocada para a fila? De acordo com meus cálculos (
sizeof(receive_t)
+ 512) * 1000 bytes devem ser alocados.MAX_PACKET_LENGTH: 512
- Posso anexar um retorno de chamada ou um gancho à minha rotina de alocação de memória para poder detectar quando minha fila solicita memória adicional?
Você pode usar os truques vinculados para obter o contêiner subjacente e, à medida que o utiliza
std::vector
como contêiner subjacente, poderá obter a capacidade.queue<T,std::vector>
alocará empush
ifsize < capacity
.capacity * sizeof(T)
T
, useq.size() * 512
Existe uma maneira de acessar o contêiner subjacente dos adaptadores de contêiner STL ?
demonstração godbolt
Uma maneira mais genérica de obter a memória alocada é usar um alocador personalizado para
std::vector<request_t, MyAllocator>
estd::basic_string<char, std::char_traits<char>, MyAllocator>
e em seu alocador personalizado você pode controlar todas as alocações, caso contrário, você pode usar um criador de perfil de heap para instrumentar o alocador global e obter a memória para cada objeto. (Eu sei que o valgrind e o intel VTune podem fazer isso)Se você deseja desempenho determinÃstico, não use
std::queue
. Se você usarstd::vector
como contêiner subjacente,pop
o atraso dependerá do número de itens na fila e, sepush
alocado,malloc
será muito não determinÃstico (o pior caso é de algumas centenas de microssegundos a um milissegundo, mais o tempo para mover todos os elementos).Em vez disso, use um buffer circular de tamanho fixo. Um bom exemplo da interface está em Boost.Circular Buffer , mas você pode implementar o seu próprio em cerca de 30 linhas se não quiser usar o boost. Ambos funcionam apenas em um único elemento
push
epop
não alocam memória em tempo de execução. Você também pode agrupar as strings usadas usando um pool de objetos para evitar todas as alocações.uma das regras para código determinÃstico é que você não aloca memória durante o tempo de execução, apenas na inicialização.