AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 78689825
Accepted
i like bananas
i like bananas
Asked: 2024-07-01 05:17:25 +0800 CST2024-07-01 05:17:25 +0800 CST 2024-07-01 05:17:25 +0800 CST

Como armazenar itens na pilha LIFO de maneira amigável ao cache?

  • 772

EDITAR / AVISO LEGAL:

Parece que meu entendimento das linhas de cache estava errado, o que torna esta questão irrelevante e enganosa. Pensei que sempre que a CPU tenta buscar uma memória em um índice específico, ela também captura índices logo após o primeiro, o que NÃO é verdade. Consulte Como funcionam as linhas de cache? para referência.


Eu estava prestes a escrever um contêiner de dados para armazenar um bloco de memória contínuo e redimensionável, no qual os itens só seriam possíveis de acessar de um lado, pressionando ou popping - basicamente uma pilha LIFO. Tenho lido muito sobre cache da CPU e padrões de acesso à memória e queria que esse contêiner fosse o mais amigável possível ao cache.

Então, dei uma olhada nas implementações comuns de pilhas LIFO na Internet. A maioria deles sugere usar um array dinâmico como base e acessar os dados anexando ou removendo itens do final do array. Neste caso, a lacuna de capacidade vazia é armazenada após os dados da seguinte maneira:

 stack bottom            stack top
 array begin             V  array end
 V                       V  V
|V          data         V |V     gap     |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|8 |7 |6 |5 |4 |3 |2 |1 |0 |  |  |  |  |  |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
                        |       cache line       |

No entanto, isso não me parece muito amigável ao cache. Sempre que alguém procura o item no topo da pilha, a CPU busca a memória do espaço que contém lixo, ou pelo menos é assim que eu entendo.

A abordagem onde a lacuna aparece como o início do bloco de memória e os dados no final teria melhor desempenho? Neste caso os índices dos itens seriam invertidos, assim como inferior e superior. Neste caso a linha de cache poderia atingir mais itens como este:

                stack top               stack bottom
                V                       V
|      gap     |V          data         V |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|  |  |  |  |  |0 |1 |2 |3 |4 |5 |6 |7 |8 |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
               |       cache line      |

Meu entendimento está correto aqui? Qual abordagem tem melhor desempenho e é mais amigável ao cache?

Posso estar totalmente errado com minhas suposições. Como eu disse, a maioria das implementações que vi usam a primeira abordagem, então deve haver algo nisso.

Saúde!

algorithm
  • 1 1 respostas
  • 55 Views

1 respostas

  • Voted
  1. Best Answer
    Peter Cordes
    2024-07-01T13:41:50+08:002024-07-01T13:41:50+08:00

    As pilhas LIFO que usam uma matriz são igualmente compatíveis com o cache para qualquer direção de crescimento, a menos que você tenha um padrão específico de tamanhos que favoreça uma alocação de tamanho ímpar e um crescimento decrescente.

    APIs para realocação eficiente (sem copiar os dados), como Linux mremapou C, reallocsão projetadas para adicionar novo espaço no final de uma alocação, não no início, então esse é um ponto a favor da maneira normal se sua pilha puder crescer além da alocação inicial . Pelo menos se você estiver usando uma API de alocação que suporte isso, não como o C++ prejudicado new/ deleteque essencialmente força std::vectora ser uma merda.

    Fora isso, eles são iguais, a menos que seu limite máximo seja geralmente 1 ou 2 elementos a mais que um múltiplo de 64 bytes, como você mostrou aqui para fazer sua outra versão parecer boa. Nessa versão, o primeiro elemento enviado está sozinho em uma linha de cache, mas o topo da pilha ainda não cruzou para uma nova linha de cache.

    Se você inserir mais um elemento em seu segundo diagrama, ele será o único elemento em uso em sua linha de cache. Parece bom apenas porque você escolheu um número de elementos para o estado atual da pilha que funciona bem com o desalinhamento (em relação aos limites da linha de cache) escolhido para o primeiro elemento (a "parte inferior" da pilha, no ponto mais alto endereço para sua pilha crescente).

    Com seu design de lacuna na frente crescente, potencialmente o primeiro elemento enviado (endereço mais alto) está na mesma linha de cache que alguns outros dados úteis, de modo que a linha de cache permanecendo quente pode ser útil (se sua pilha frequentemente fica vazio para que você realmente acesse esse elemento).
    Os alocadores de memória geralmente arredondam as alocações para múltiplos de tamanho maior, como 16 bytes, mas ainda pode haver outras alocações em uma linha de cache.
    Ainda assim, a menos que você saiba algo especial sobre os tamanhos de pilha esperados e/ou o que vem a seguir, normalmente você desejaria alocar um pedaço de memória que seja um múltiplo do tamanho da linha de cache.

    Curiosidade: a pilha de chamadas asm diminui nos ISAs convencionais (e nas convenções de chamada para ISAs como MIPS, que não favorecem uma direção de crescimento da pilha). por exemplo, x86 pushe calldiminuir o registro de ponteiro de pilha (RSP). As razões para isso não são a eficiência do cache, mas sim históricas , que remontam a antes das CPUs terem caches. No entanto, não apresenta problemas específicos para caches de CPU.

    As pilhas de CPU/asm são alocadas de forma que a linha de cache de endereço mais alto seja totalmente usada, ao contrário da sua, onde o fim da alocação não é o fim de uma linha de cache. (Normalmente, "a pilha" é um múltiplo do tamanho da página, portanto, de qualquer maneira, não haverá outras coisas próximas a ela na mesma linha.)

    • 1

relate perguntas

  • Encontre o menor número inteiro positivo, que não divide nenhuma diferença mútua de inteiros em uma matriz

  • O último dígito de um grande número de casos de teste falha em Golang Codewars

  • Escreva um programa LMC que calcule a soma dos números inseridos pelo usuário. Exibir soma antes de parar

  • Como determinar os estados alcançáveis ​​no problema de 3 jarras de água?

  • Encontre o número de pares de números naturais de l a r que bit a bit AND é igual a 0

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle?

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Quando devo usar um std::inplace_vector em vez de um std::vector?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Martin Hope
    Aleksandr Dubinsky Por que a correspondência de padrões com o switch no InetAddress falha com 'não cobre todos os valores de entrada possíveis'? 2024-12-23 06:56:21 +0800 CST
  • Martin Hope
    Phillip Borge Por que esse código Java simples e pequeno roda 30x mais rápido em todas as JVMs Graal, mas não em nenhuma JVM Oracle? 2024-12-12 20:46:46 +0800 CST
  • Martin Hope
    Oodini Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores? 2024-12-12 06:27:11 +0800 CST
  • Martin Hope
    sleeptightAnsiC `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso? 2024-11-09 07:18:53 +0800 CST
  • Martin Hope
    The Mad Gamer Quando devo usar um std::inplace_vector em vez de um std::vector? 2024-10-29 23:01:00 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST
  • Martin Hope
    MarkB Por que o GCC gera código que executa condicionalmente uma implementação SIMD? 2024-02-17 06:17:14 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve