2010-05-22 32 views
7

Principalmente esta parece ser una técnica utilizada por juegos, donde tienen todos los sonidos en un archivo, texturas en otro etc. Con estos archivos comúnmente alcanzan el tamaño GB.Motivo de los archivos de datos monolíticos

¿Cuál es la razón detrás de hacer esto para mantener todo en subdirectorios como archivos pequeños, uno por textura que utilizan muchos juegos pequeños, con el sistema monolítico favorecido por las empresas más grandes?

¿Hay alguna sobrecarga del sistema de archivos con muchos archivos pequeños? ¿Están tratando de proteger su propiedad, aunque la mayoría parece ser un archivo comprimido con una nueva extensión?

Respuesta

6

Las razones que utilizamos un sistema de "archivo" como esta en la que trabajo (una compañía de desarrollo de juegos):

  • velocidad de búsqueda: Rara vez necesitamos iterar sobre los archivos en un directorio; estamos mucho más a menudo buscándolos directamente por su nombre. Al usar una "tabla de asignación de archivos" personalizada que es esencialmente solo una secuencia de hash(normalized_filename) -> [ offset, size ], podemos buscar los archivos muy rápidamente. También podemos mantener este índice en la RAM, potencialmente intercalarlo con otras tablas de índice, etc.
  • (Cuando necesitamos iterar, podemos iterar fácilmente sobre todos los archivos en un .arc, o podemos almacenar una lista de nombres de archivos , una lista de nombres de hash-de-archivos, o simplemente una lista de pares de [desplazamiento, tamaño] en algún lugar, tal vez incluso como un archivo en el archivo. Esto es generalmente más rápido que un recorrido de directorio en un FS)
  • metadata: Es fácil para nosotros incluir todos los metadatos de archivos que queremos. Por ejemplo, un solo bit en el campo "tamaño" indica si el archivo está comprimido o no (si es así, tiene un encabezado con más detalles sobre cómo descomprimirlo). Incluso podemos variar la compresión en partes de un archivo si sabemos lo suficiente sobre la estructura del archivo antes de tiempo (hacemos esto para los archivos de sprites).
  • tamaño: Uno de los dispositivos que utilizamos tiene un requisito de "tamaño de archivo debe ser un múltiplo de X", donde X es grande en comparación con algunos de nuestros archivos. Por ejemplo, algunos de nuestros scripts de lua terminan siendo unos cientos de bytes cuando se compilan; tomar sobrecarga adicional por archivo .luc se acumula rápidamente.
  • alineación: por otro lado, a veces queremos para perder espacio. Para aprovechar la transmisión más rápida (por ejemplo, DMA de fondo) desde el sistema de archivos, algunos de nuestros archivos hacen desean cumplir con ciertos requisitos de alineación/tamaño. Podemos ocuparnos de ese derecho en la herramienta, y la alineación/tamaño que estamos buscando no necesariamente tiene que estar en línea con el FS subyacente, lo que nos permite desperdiciar espacio solo donde lo necesitamos.

Pero esas son las razones mundanas. Las cosas más divertidas:

Cada .arc se registra en una lista e intenta abrir un archivo para mirar los arcos.Primero buscamos los archivos que ya están en RAM, luego los archivamos en el dispositivo FS, luego en el dispositivo real FS. Esto nos da una tonelada de flexibilidad:

  • adiciones dinámicas en el sistema de archivos: en cualquier momento se puede transmitir un nuevo archivo o archivo a la máquina en cuestión (por la red o similar) y hacer que aparezca como parte del sistema de archivos "lógico"; esto es genial cuando el FS actual reside en la ROM o en un CD, y nos permite iterar mucho más rápido de lo que podríamos hacerlo.
  • (sistema de Doom .wad es una especie de ejemplo de lo anterior, lo que permite a los modders para anular más fácilmente activos y secuencias de comandos integradas en el juego.)
  • posibilidad de no fs subyacentes: Es posible utilizar bin2obj Para incrustar un arco completo directamente en el ejecutable (.rodata) en el momento del enlace, momento en el que no necesita mirar el dispositivo FS, lo hacemos para ciertas compilaciones de demostración pequeñas y similares. También podemos enviar niveles a través de la red o savegame-sneakernet de esta manera. =)
  • organización y carga/descarga: ya que podemos cargar y descargar y anular "piezas" virtuales de nuestro sistema de archivos en cualquier momento, podemos hacer algunos trucos de rendimiento para que el número de archivos en el FS sea muy pequeño en cualquier momento dado. Además, podemos especificar que se cargue un archivo completo en la memoria, tabla de índice y datos; nuestro código de carga de archivos es lo suficientemente inteligente como para saber que si el archivo ya está en la memoria, no necesita hacer nada para leerlo más que mover un puntero. Algunos de los códigos de nivel superior realmente pueden detectar que el archivo está en RAM y solo solicitan el puntero probablemente ya se parece a una estructura directamente.
  • portabilidad: solo tenemos que averiguar cómo obtener algunos archivos en cada dispositivo nuevo que usamos, y luego el resto del código FS es más o menos el mismo. =) Cambiamos la salida de la herramienta un poco ocasionalmente (por razones de alineación), pero la mayor parte del procesamiento sigue siendo el mismo.
  • deduplicación: con archivos más inteligentes, como nuestros archivos sprite, podemos (y lo hacemos) duplicar los datos. Si el quinto marco de la animación "saltar" y el tercer cuadro de "retroceso" son iguales, podemos separar el archivo y solo almacenar una copia de ese marco. Podemos hacer lo mismo con los archivos completos.

Llevamos un juego de PC a un sistema con acceso FS mucho más lento recientemente. No cambiamos el formato de los datos, y resulta que iterar a través de un directorio en el dispositivo en bruto FS para cargar un centenar de pequeños archivos XML estaba matando nuestros tiempos de carga. La solución que utilizamos fue tomar cada dir, convertirlo en su propio subdir.arc, y pegarlo en el maestro game.arc comprimido. Cuando se necesitaba el directorio (se llamaba algo así como opendir), descomprimimos todo el subdir.arc en la memoria RAM, lo agregamos al sistema de archivos y luego lo repetíamos súper rápido.

Es la capacidad de lanzar algo como esto en unas pocas horas, y para aliviar el dolor de portar a través de los sistemas, que hace que cosas como esta valgan la pena.

+0

jaja +1 me gusta esta respuesta. Me olvidé por completo de la alineación, los trozos y las piezas de transmisión. Las otras razones también son geniales. –

+0

+1 Buena respuesta. También los archivos personalizados le permiten configurar las opciones de almacenamiento por fragmento de datos de archivo, es decir, variar el formato de compresión, la alineación de datos por tipo de recurso, etc. – zebrabox

+0

@zebrabox: oh sí, me olvidé de eso. En otro formato de archivo (específico del sprite) que usamos, comprimimos el marco por separado de los metadatos, y hacemos una deduplicación automática para los marcos que terminan siendo los mismos, incluso entre diferentes sprites. – leander

1

Los sistemas de archivos tienen una sobrecarga. Normalmente, un archivo ocupa espacio en disco redondeado a una potencia de 2 (por ejemplo, hasta 4 KB), por lo que muchos archivos pequeños perderían espacio. Algunos sistemas de archivos modernos intentan mitigar eso, pero AFAIK aún no está muy extendido. Además, los sistemas de archivos a menudo son bastante lentos al acceder a múltiples archivos. P.ej. generalmente es considerablemente más rápido copiar un archivo de 400 MB que 4000 archivos de 100 KB.

Los sistemas de archivos son útiles cuando tiene que modificar los archivos, ya que manejan los tamaños de archivo cambiantes mucho mejor que cualquier solución simple local. Sin embargo, ciertamente ese no es el caso para los datos constantes del juego.

+0

Cualquier textura decente es probable que supere la marca de 4 KB, sin duda los sonidos serán. ¿Entonces una posible instalación más rápida es la razón principal? Por cuánto supongo que depende del sistema de archivos. –

+0

No importa si la textura supera la marca de 4 KB: aún desperdicia espacio, hasta el siguiente múltiplo de 4 KB. – Kylotan

0

En los sistemas Apple, la forma más común es utilizar, como usted sugiere, los directorios. Se llaman Bundles, y están en Finder representados como un solo archivo, pero si los exploras más, en realidad son directorios. Esto hace que escribir código y conservar memoria al cargar elementos individuales de este paquete sea muy fácil. :-) Además, esto facilita la realización de copias de seguridad incrementales de bases de datos gigantescas, como por ejemplo su base de datos iPhoto es solo un paquete, por lo que solo copia de seguridad de archivos nuevos y modificados

En Windows, sin embargo, creo que esto es mucho más difícil hacer, se verá como un directorio "no importa qué" (estoy seguro de que las personas inteligentes han encontrado una solución que hará que Explorer vea ciertos directorios como un único archivo, pero no es común).

Desde el punto de vista del desarrollador de juegos, no se trata de archivos tan pequeños que la sobrecarga de espacio en el disco es algo que le preocupa mucho, así que dudo la sugerencia de @ doublep, ya que hace una molestia, pero hace que sea mucho más fácil con un solo archivo si los usuarios deben copiar un juego completo en alguna parte, entonces es fácil verificar si todo el conjunto es correcto.

Y, por supuesto, es más difícil de leer para las personas que no deberían tener acceso. Pero también es más difícil de modificar, lo que significa que es más difícil parchear y más difícil escribir extensiones. Alguien que usa extensiones mucho, prefiere la estructura del directorio: Los Sims.

Si yo fuera el desarrollador de juegos, me encantaría buscar archivos individuales. Por otra parte, yo estaría utilizando haces como que estaría escribiendo para el Mac ;-)

Saludos

Nik

+0

Ver ciertos directorios como un solo archivo: archivo zip en modo 'store' (sin compresión). Lo interesante es que a veces es solo un archivo de datos monolítico, pero tiene un directorio completo como estructura dentro. Así que todavía hay otra razón para usar un archivo, que no es fácil de copiar a otras computadoras (todas esas molestas claves de registro que les gusta agregar). –

0

puedo pensar en varias razones.

Como se sugirió doble, los archivos ocupan más espacio del que requieren. Entonces un archivo ahorra espacio. 10k archivos (de cualquier tamaño) deberían ahorrarle 20MB cuando se empaquetan en un archivo. No es exactamente una gran cantidad de espacio hoy en día, pero aún así.

La otra razón que puedo pensar es en la fragmentación de discos.Sospecho que un disco muy fragmentado funcionará peor cuando acceda a miles de archivos separados en un espacio fragmentado. Pero no soy un experto en este campo, por lo que agradecería que alguien más experimentado verificara esto.

Finalmente, creo que esto también puede tener algo que ver con restringir el acceso a archivos de juegos separados. Puede tener un montón de scripts de Lua expuestos, meterse con ellos y romper algo. O puede tener el outro cinematográfico/sonido/texto/lo que sea expuesto y se echan a perder al acceder a él. También lo hago yo mismo: encripto las imágenes con una clave XOR multipasa, empaqueté archivos de texto y variables de configuración en un archivo monolítico (comprimido para mayor seguridad) y solo dejo la música a libre acceso. De esta forma, los secretos del juego permanecerán ocultos durante un poco más de tiempo :).

O puede haber otra razón por la que nunca pensé: D.

+0

Dudo que la fragmentación del disco sea la razón principal (no hay problema en Linux fs) y vista en adelante lo hace automáticamente. Guardar secretos parece la posibilidad más probable ya que es favorecido por las grandes editoriales. –

+0

En realidad, recuerdo que guardar secretos no tenía nada que ver, ya que los datos se encriptaban en el disco (varias técnicas) y el hardware en GC, y creo que PS lo descifró sobre la marcha. También podría hacer esto en archivos pequeños, pero la razón principal es el rendimiento. dependiendo del tipo de juego, puede tener cientos de archivos para un nivel que es horrible de cargar. Incluso en el código (supongo que podría generar una lista, pero generar un archivo es bastante fácil) –

0

Como sabes, los juegos, especialmente con las compañías más grandes, intentan exprimir tanto rendimiento como puedan. Una técnica es tener todos los datos en un archivo grande y simplemente DMA a la memoria (piénselo como una memoria de CD a RAM). Dado que todos los archivos están en uno grande, no habrá búsquedas de disco y puede tener una gran cantidad de archivos (lo que puede causar una gran cantidad de búsquedas), todos cargados rápidamente debido a la técnica.

+0

Presumiblemente, esto solo se ha convertido en una opción viable en los últimos años, almacenar alrededor de 1GB en ram (aproximadamente la cantidad que Crysis toma de mí) es solo es posible cuando se puede garantizar que el usuario TENDRÁ varios GB de ram, ya que tan pronto como se localice, ya no valdrá la pena hacerlo. ¿Qué hay de solo poner parte de un archivo de datos en DMA (es posible o vale la pena?). –

+1

DMA = acceso directo a la memoria. Es como una transferencia y no un lugar para el almacenamiento. En los primeros días casi todo usaría DMA ya que había poca velocidad. Esto siempre ha sido hecho. Pero hay ocasiones en las que no se usa un archivo grande como DLL. por eso es que ves tantos. Por lo general, todos los juegos usan archivos monolíticos a menos que estén destinados a editarse o los tiempos de carga sean lo suficientemente rápidos sin cambiarlos. –

Cuestiones relacionadas