2009-05-13 15 views
6

La regla de oro es que está bien pasar estructuras pequeñas por valor y las más grandes deben hacerse por punteros.¿Cómo se pueden pasar las estructuras grandes por valor de manera eficiente?

Mi pregunta es dónde exactamente está este punto de corte? ¿Qué tan grandes pueden ser las estructuras antes de que sea mejor pasarlas por puntero?

Sé que esto variará según las plataformas, pero supongo que se podrían dar algunas estimaciones aproximadas. Hace un año o dos intenté descubrir esto en la arquitectura de PPC y me sorprendió que uno pudiera pasar una gran cantidad de datos de manera eficiente por valor. Piense en 10 valores dobles más o menos estuvo bien debido a la gran cantidad de registros en PPC. Por puntero realmente involucraba más copia dentro y fuera de la memoria.

Sin embargo, ahora estoy en Intel y espero que las cosas puedan ser diferentes. Dado que la CPU no tiene tantos registros tradicionalmente, pero tal vez eso es diferente en los registros de 64 bits o coma flotante?

+4

Depende .... Necesita hacer referencia ... –

+1

Mitch es correcto, la única forma de saberlo es con un punto de referencia. Y tu respuesta variará según la plataforma en la que pruebes. –

+0

Supongo que mi problema es que no sé cómo marcarlo adecuadamente. Me temo que un ejemplo simple será optimizado demasiado fácilmente por el compilador, y no reflejará el uso real. Puede parecer estúpido hacer una optimización prematura, pero esto es algo con lo que he luchado para tener un buen rendimiento, así que no quiero tomar una decisión estúpida innecesaria. Afectará mi diseño completo de API, por lo que no quiero tener que cambiar todo esto más adelante. –

Respuesta

1

Bien, así que traté de seguir los consejos y el perfil de mi código con el uso de punteros y el valor. También miré el código de ensamblaje. Parece que las características de rendimiento en x86 son bastante diferentes de PPC. En PPC, la interfaz binaria a C especificó que los argumentos se colocarían en registros (había tantos para elegir), sin embargo, parece que incluso en 64bit x86 se requieren argumentos para poner en la pila.

Esto explica por qué en x86 el puntero de paso siempre parece ser más rápido. Sin embargo, noté que el compilador está muy ansioso por alinearse. Entonces no importó de qué manera lo hice. Así que supongo que la conclusión es usar el pase que sea conveniente para ti.

Creo que favorece la transferencia de valor, porque trabajar en copias de valores es algo más seguro. Mi caso de prueba fue una estructura que consta de 4 dobles (así que supongo que eso hace que sea de 32 bytes en la mayoría de las plataformas).

4

Si busca en la web, encontrará algunas pautas sobre el tamaño del byte para pasar por referencia y valor. Yo no confiaría en nada de eso. La única manera de saber que una estructura particular, es un problema es

Perfil Es

Ésta es la única manera de saber 100% de que hay un problema.

Antes de que los detractores salten. Sí, hay algunos casos obvios por ahí. Por ejemplo, nunca aprobaría una estructura por valor si tuviera, por ejemplo, 100 miembros. Pero eso no sería por problemas de rendimiento, sería más por problemas de espacio en la pila.

+0

Votación a la baja. Esta no es una respuesta: no le diga a la gente que busque en la web. Publica los hechos y refiérete a ellos. –

0

No descuides la parte que la alineación juega en tus pruebas. Si está pasando flotadores o dobles alrededor y sus estructuras no están alineadas en los límites apropiados, el procesador puede terminar recuperando una parte de su valor, cambiándolo y luego colocando el resto antes de almacenarlo. Creo que la mayoría de los compiladores modernos se DTRT (alineando la estructura cuando se declara), pero si se está optimizando para el espacio, entonces esto probablemente será un problema.

Hmmm, ahora que pienso en ello, tomar esto con un grano de sal, ya que no he hecho ningún tipo de codificación de bajo nivel en la arquitectura x86 desde el Pentium Pro ...

0

Algunos compiladores haga la determinación del tamaño óptimo para usted. Si mal no recuerdo, el compilador TI28xx convierte automáticamente el pase por valor para pasar por referencia si la estructura está por encima de un determinado tamaño.

2

En C++ no es la regla para pasar todo no en la siguiente lista como const referencia porque los Performanceis esencialmente nunca peor. La lista de excepciones es:

tipos
  • elementales (int etc.),
  • punteros,
  • tipos vacías (tipos),
  • tipos de función (como funtores), y
  • iteradores.

No estoy seguro de si esto se puede aplicar directamente a C (aparte de los tipos obvios que C no tiene) pero tal vez se aplique una directiva similar.

+0

Sigo este patrón cuando programo C++, pero estrictamente hablando no estoy seguro de que siempre sea óptimo. Por lo que sé const MyClass & var, se implementa como const pointer. Y para objetos pequeños (por ejemplo, digamos 2-3 dobles), el indicador de pase es más lento que el valor de paso. –

+0

El acceso a punteros, por supuesto, incurre en gastos generales, pero los fabricantes de procesadores son conscientes de la necesidad de punteros. Como tal, toman precauciones. La guía de optimización de AMD, por ejemplo, explica explícitamente el uso de punteros aquí porque el procesador se desarrolla teniendo en cuenta ese uso. Para resumir: incluso para estructuras pequeñas, los punteros podrían ser más rápidos que pasar por valor. Inline puede, por supuesto, modificar este comportamiento aún más. –

+0

¿Hay alguna fuente "oficial" de la lista de excepciones que ha publicado? Estaba listo para escribir una pregunta sobre el tiempo, tiene sentido pasar los tipos elementales por referencia. –

-1

Por lo general, los tipos primitivos paso por valor, todo lo demás por referencia. Esa es mi regla de oro.

+4

La pregunta es sobre el rendimiento, no sobre sus reglas. – stepancheg

Cuestiones relacionadas