¿Cómo hacer perfiles y agrupaciones de memoria por sistema?


8

Me ha interesado crear perfiles y mantener un grupo de memoria administrada para cada subsistema, de modo que pueda obtener estadísticas sobre cuánta memoria se está utilizando en algo como sonidos o gráficos. Sin embargo, ¿cuál sería un diseño que funcione para hacer esto? Estaba pensando en usar múltiples asignadores y solo usar uno por subsistema, sin embargo, eso daría como resultado variables globales para mis asignadores (o eso me parece a mí). Otro enfoque que he visto / sugerido es simplemente sobrecargar nuevo y pasar un asignador para un parámetro.

Tuve una pregunta similar sobre stackoverflow aquí con una recompensa, sin embargo, parece que tal vez fui demasiado vago o simplemente no hay suficientes personas con conocimiento en el tema.


Eliminó mi respuesta. Regresé y leí los artículos y los grupos utilizados para rastrear las asignaciones por sistema no son parte de esos artículos (a pesar de que se basaron en él). Si puedo encontrar esos específicos nuevamente, los vincularé. ¡Lo siento!
James

1
Echa un vistazo a esta publicación de blog de Jesús de Santos García. En él, analiza el seguimiento de la memoria por subsistema y el uso de múltiples asignadores para diversos requisitos de memoria.

77
No te obsesiones con los paradigmas teóricos. Si necesita funcionalidad y datos a nivel mundial, entonces no hay nada malo con los globales. Ya hay un montón de funciones globales como new / delete / malloc / free. Simplemente agregue lo que tiene que hacer para hacer el trabajo.
Maik Semder

Respuestas:


1

Definitivamente es una pregunta que puede sonar vaga para algunos;)

Pero creo que sé de dónde vienes.

Tiene un millón de opciones para elegir cómo implementar esto. Algunas de esas opciones deben girar en torno a las plataformas de destino y los objetivos generales de diseño. Esas consideraciones romperán cualquier vínculo, hasta que se sienta lo suficientemente cómodo con diferentes costos de implementación suficientes para hacer crecer primero el diseño de la plataforma y las preocupaciones generales de diseño. Hasta entonces, aquí hay algunas formas que no le costarán en términos de complejidad (carga de gestión) o en el tratamiento de la eliminación o los cambios si cambia de opinión ...

Si el objetivo es medir y asignar, con la posibilidad de usar grupos, primero debe pensar en el conjunto mínimo de código habitable para comenzar. En aras de la explicación, si eres parcial a las clases, puedes hacer una clase, dejar que represente un montón, o en su lugar usar un conjunto de funciones que toman un identificador o un nombre de montón. Es realmente una cuestión de semántica para ser honesto. La siguiente decisión es nueva o malloc; Soy parcial con malloc porque muchas veces estoy lidiando con construcciones de bajo nivel y sé en la mayoría de las implementaciones que las nuevas llamadas son malloc, y no tengo que preocuparme por la complejidad de sobrecargar nuevas y preocuparme por eso en todas las plataformas . Sin embargo, muchas veces he construido sistemas o componentes alrededor de sobrecargas o conexiones nuevas. Y, por supuesto, el problema central o la diferencia es que 'nuevo' debe conocer el tipo antes de la asignación, donde a 'malloc' no le importa y con malloc resuelve un tipo después de la asignación. Todo ese detalle es para darle una idea y algo de contexto para tomar decisiones de diseño en este tipo de asuntos :)

Así que voy a elegir class y malloc, porque es más fácil de explicar aquí, pero al final no importa. Las partes internas terminarán teniendo poca diferencia de material en comparación con el resto del diseño general.

Entonces, en este caso hipotético, sé que (o voy a suponer que) puedo terminar con 7-8 instancias de clase de subsistema reales y anticipar cientos de miles de llamadas para asignación y gratis. Dado que gran parte de mi curiosidad y empuje real en todo esto se trata realmente de los tamaños y el lado del perfil, no quiero cargar el rendimiento de la aplicación. Para empezar, podría decidir dejar todo abierto y público hasta que lo tenga clavado, mientras paso por la implementación en el resto de la aplicación; Una estructura lo hará muy bien. La 's_' es para mostrar qué variables están claramente destinadas a las estadísticas.

struct Mem
{
  int s_allocs;
  int s_frees;
  int s_peak;
  int s_current;
  void* heap; // if you wanted to go into having real actual separate heaps, else ignore
  void* alloc(int size);
  void free(void* p);

  Mem() {memset(this,0,szieof(Mem));}  // want this to be inlined with the call site constructor (a design decision example)
}

class MySubSystem
{
   Mem mem;
   ....  you get the idea
}

Esto es extremadamenteligero en muchos frentes, y tal vez un buen lugar para comenzar a desarrollar donde realmente quisieras ir con esto. E inmediatamente tiene un problema, ¿cómo sabe el tamaño del artículo liberado? (Esto sería un problema para resolver en casi cualquier enfoque). Dado que este es un foro de juegos, podría considerar doblar los primeros bytes con el tamaño, o de lo contrario tendrá que ajustar o recordar de alguna otra manera. La mayoría de las sensibilidades de los desarrolladores de juegos no deberían ser demasiado contra el dopaje, y es el ejemplo más simple, teniendo en cuenta que ya he hecho un muro de texto. Básicamente es así: no quieres saber si se puede ayudar a destruir la alineación inherente, sí quieres saber, ya que casi gratis, si el tamaño es coherente. Entonces, algo tan simple como "s_allocs ++; s_total + = size; uint64 * p = (uint64 *) malloc / calloc (size + = 8); * p = 0xDEADDAED00000000 | Talla; return p + 1; "donde las asignaciones serán inferiores a 4 GB, y uint64 es lo que el compilador cree que es un int sin signo de 64 bits, y donde puede verificar el valor de cordura de forma gratuita.

Esta es una forma de obtener el mínimo a un costo mínimo que satisfaga los requisitos. Lo hace nodireccione las clases de asignación que tienen funciones virtuales si están dentro del alcance para la creación de perfiles o la administración, ya que no puede anticipar el tamaño que el entorno de C ++ que está utilizando necesita para aquellos sin sobrecargar o conectar nuevos, o si confía en el constructor en uno de los formas extrañas que no podrían ser manejadas por alguna otra función 'init'. De lo contrario, un stuct es una clase es una asignación arbitraria y es todo lo mismo, cuando lanzas. Si eres parcial a lo nuevo y necesitas la tabla virtual inherente o la semántica del constructor, entonces debes enganchar lo nuevo, pero ese es un animal completamente diferente, que debes estudiar realmente para asegurarte de que estás haciendo lo que las nuevas necesidades tienen que indicar. su código está manejando nuevo, a qué cubo se aplica esto. Pero por lo demás, el concepto anterior es el mismo.

Más importante aún, esto debería hacer que tu cerebro funcione, y con suerte en la línea de lo que necesitas y cuáles son tus tolerancias, ahora que has visto un poco más detrás de la cortina. No hay mago :)


Si estaba utilizando funciones de plantilla para asignar y liberar, no debería ser un problema determinar el tamaño necesario para ser liberado (y asignado).
API-Beast

1
El punto era mostrar el problema subyacente para ayudar a proporcionar una base para elegir cualquier abstracción, no para presentar una abstracción particular. Todo tiene sus compensaciones. El conocimiento del tamaño es necesario no para hacer el acto de liberación, sino para las estadísticas.
Celess

1

No necesitas implementar nada en tu juego para estos datos. Herramientas como Massif Valgrind pueden extraer todos los datos necesarios de los símbolos de depuración. Puede ver los volcados de Massif en Massif Visualizer .


44
Supongo que, desafortunadamente, la mayoría de los juegos gráficos no se desarrollarán en un sistema que ejecute Valgrind.
Kylotan el

1

Recomiendo no escribir su propio asignador de memoria. Necesita uno estable, confiable y probado, con una buena funcionalidad de depuración como detección de corrupción y lo más importante: con estadísticas confiables. Esta no es una tarea fácil y tiene muchas dificultades. Hay excelentes y fáciles de utilizar, por ejemplo:

Doug Lea Allocator

Viene con el concepto de espacios de memoria, puede usar uno por subsistema. Está altamente optimizado y le brinda excelentes estadísticas e información de tiempo de ejecución.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.