Pergunta

Atualmente estou trabalhando em um ray-tracer em C# como um hobby.Eu estou tentando conseguir uma boa velocidade de renderização através da implementação de alguns truques de uma implementação c++ e tem executado em um lugar de angústia.

Os objetos nas cenas que a ray-tracer presta são armazenados em um KdTree estrutura e nós da árvore são, por sua vez, armazenados em uma matriz.A otimização estou tendo problemas com é ao tentar encaixar o máximo de nós de árvore possível em uma linha de cache.Um dos meios de se fazer isso é para nós para conter um ponteiro para a esquerda do nó filho só.Em seguida, ele é implícito que o direito da criança segue diretamente após o esquerdo na matriz.

Os nós são estruturas e durante a construção da árvore, eles são com sucesso colocado na matriz por um estáticos do gestor de memória de classe.Quando eu começar a percorrer a árvore que, à primeira vista, parece funcionar muito bem.Em seguida, em um ponto de início do processamento (sobre o mesmo lugar de cada vez), filho à esquerda do ponteiro do nó raiz é, de repente, apontando para um ponteiro nulo.Eu cheguei à conclusão de que o lixo collecter mudou as estruturas como a matriz fica na pilha.

Eu tentei várias coisas para fixar os endereços na memória, mas nenhum deles parece durar para toda a vida útil do aplicativo, como eu preciso.O "fixo", palavra-chave só parece ajudar, durante a chamadas de método e de declarar "fixo", matrizes pode ser feito apenas em tipos simples que um nó não.Há uma boa maneira de fazer isso ou eu estou muito longe no caminho de coisas C# não era destinado.

Btw, mudando para c++, enquanto que, talvez, a melhor escolha para um alto desempenho do programa, não é uma opção.

Foi útil?

Solução

Em primeiro lugar, se você estiver usando C#, normalmente, você não pode começar de repente uma referência nula, devido ao coletor de lixo mover coisas, porque o coletor de lixo também atualiza todas as referências, assim você não precisa se preocupar com isso mover coisas ao redor.

Você pode fixar as coisas em memória, mas isso pode causar mais problemas do que resolve.Por um lado, impede que o coletor de lixo de compactação de memória corretamente, e pode afetar o desempenho dessa maneira.

Uma coisa que eu gostaria de dizer do seu post é que, utilizando estruturas não podem ajudar o desempenho como você espera.C# falha para linha de quaisquer chamadas de método envolvendo estruturas, e mesmo que tenham corrigido isso no seu mais recente do runtime beta, estruturas frequentemente não realizar o bem.

Pessoalmente, eu diria que C++ truques como este, de modo geral, não costumam transitar muito bem em C#.Você pode aprender a deixar ir um pouco;pode haver outras formas mais sutis para melhorar o desempenho ;)

Outras dicas

Qual é a sua estáticos do gerenciador de memória, na verdade está fazendo?A menos que ele está fazendo algo inseguro (P/Invoke, de código não seguro), o comportamento que você está vendo é um erro em seu programa, e não devido a comportamento de CLR.

Em segundo lugar, o que você quer dizer por 'ponteiro', com respeito às relações entre as estruturas?Você, literalmente, significa uma inseguro KdTree* ponteiro?Não faça isso.Em vez disso, use um índice para o array.Desde que eu esperava que todos os nós de uma única árvore são armazenados na mesma matriz, você não precisa de uma referência separado para a matriz.Apenas um único índice vai fazer.

Finalmente, se você realmente deve usar KdTree* ponteiros, em seguida, seu estáticos do gerenciador de memória deve alocar um bloco grande e.g. usandoMarechal.AllocHGlobal ou outra memória não gerenciada de origem;ele deveria tratar esse grande bloco como um KdTree matriz (i.e.índice KdTree* C-estilo) e ele deve suballocate nós a partir desta matriz, por esbarrar um "livre" de ponteiro.

Se você já tem para redimensionar esta matriz, em seguida, será necessário atualizar todos os ponteiros, é claro.

A lição básica aqui é a de que não seguros ponteiros e memória gerenciada fazer não misturar, fora do 'fixo' blocos, o que, naturalmente, do quadro de pilha de afinidade (por exemplo,quando a função retorna, o preso comportamento vai-se).Há uma maneira para fixar objetos arbitrários, como sua matriz, usando GCHandle.Alloc(yourArray, GCHandleType.Fixado), mas quase de certeza que não quer ir por esse caminho.

Você vai ter mais respostas sensatas, se você descrever mais detalhadamente o que você está fazendo.

Se você realmente quero fazer isso, você pode usar o GCHandle.Alocação método para especificar que um ponteiro deve ser fixado, sem ser automaticamente lançado no final do escopo como o fixo instrução.

Mas, como outras pessoas têm a dizer, fazer isso é colocar pressão indevida sobre o coletor de lixo.Que sobre apenas a criação de uma estrutura que se agarra a um par de seus nós e, em seguida, a gestão de uma matriz de NodePairs, ao invés de incluir um conjunto de nós?

Se você realmente deseja ter completamente o acesso não gerenciado para um bloco de memória, você poderia provavelmente ser melhor alocar a memória diretamente do heap não gerenciado, ao invés de incluir permanentemente a fixação de uma parte do heap gerenciado (isso impede que a pilha de ser capaz de corretamente compacto em si).Uma maneira simples e rápida de fazer isso seria usar o Marechal.AllocHGlobal método.

É realmente proibitivo para armazenar o par de matriz de referência e o índice?

Qual é a sua estáticos do gerenciador de memória, na verdade está fazendo?A menos que ele está fazendo algo inseguro (P/Invoke, de código não seguro), o comportamento que você está vendo é um erro em seu programa, e não devido a comportamento de CLR.

Eu estava na verdade falando sobre inseguro ponteiros.O que eu queria era algo como Marshal.AllocHGlobal, embora com uma duração superior a uma única chamada de método.Na reflexão parece que apenas a utilização de um índice é a solução certa de que eu poderia ter ficado muito preso imitando o código c++.

Uma coisa que eu gostaria de dizer do seu post é que, utilizando estruturas não podem ajudar o desempenho como você espera.C# falha para linha de quaisquer chamadas de método envolvendo estruturas, e mesmo que tenham corrigido isso no seu tempo de execução mais recentes beta, estruturas frequentemente não realizar o bem.

Eu olhei para este um pouco e eu vejo isso foi corrigido .NET 3.5SP1;Eu suponho que é o que você estava se referindo a como o tempo de execução beta.Na verdade, agora eu entendo que essa mudança representou uma duplicação da minha velocidade de renderização.Agora, estruturas são agressivamente em forrado, melhorando o seu desempenho significativamente em sistemas X86 (X64 melhor estrutura de desempenho previamente).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top