• Publicidad

Abrir archivos binarios de tamaño de 50 megas con Perl

Perl aplicado a la bioinformática

Abrir archivos binarios de tamaño de 50 megas con Perl

Notapor lobnomis » 2014-05-02 11:49 @534

¿Qué tal, amigos del foro...?

Tengo un script en Perl que procesa un archivo en formato binario, el cual no tiene problemas, hasta que existan archivos de tamaño mayor a 10 Megas.

En UNIX me sale el siguiente mensaje "".
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Out of memory!
Out of memory!

Pid 6864 received a SIGSEGV for stack growth failure.
Possible causes: insufficient memory or swap space,
or stack size exceeded maxrsessiz
or stack size limit is set too small.
Memory fault(coredump)
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Pero en el servidor sí tengo RAM suficiente y también espacio en disco.

La sentencia que tengo es la siguiente read(FILE, $buffer,200000000);

No sé si es una limitación que el archivo sea de mayor a 10 megas.

Les agradecería sus comentarios.
lobnomis
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2014-05-02 11:00 @500

Publicidad

Re: Abrir archivos binarios de tamaño de 50 megas con Perl

Notapor explorer » 2014-05-03 18:56 @830

Bienvenido a los foros de Perl en Español, lobnomis.

Perl no tiene más límite que el de la memoria RAM y también según la arquitectura en que haya sido compilado (32 o 64 bits).

Así que, ese error que te sale, yo creo que es por el sistema operativo, que tendrá puestos unos límites para los procesos que se ejecutan en él.

Si es un Linux/UNIX, existe el comando ulimit -a

Por ejemplo, en mi sistema, me sale esto:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 128021
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 128021
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
Mira a ver si es una limitación del sistema.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Abrir archivos binarios de tamaño de 50 megas con Perl

Notapor lobnomis » 2014-05-03 22:26 @976

¿Qué tal, explorer?

He verificado lo que me indicaste:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
time(seconds)        unlimited
file(blocks)         unlimited
data(kbytes)         4194300
stack(kbytes)        392192
memory(kbytes)       unlimited
coredump(blocks)     4194303
nofiles(descriptors) 63488
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Estos son los datos que me salieron. De lo que puedo observar, no tendría problemas.
lobnomis
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2014-05-02 11:00 @500

Re: Abrir archivos binarios de tamaño de 50 megas con Perl

Notapor explorer » 2014-05-04 06:05 @295

Sí, ahí se ve que tienes suficiente memoria. Pero el error dice que el proceso se ha parado porque la pila ha crecido más de lo necesario.

Si el límite del proceso es de 392192 KB (392 MB), entonces es que estás llenando la pila con algo.

La línea que muestras es:

read(FILE, $buffer,200000000);

Es decir, le estás pidiendo que lea 200 MB. Dices que estás leyendo un archivo de 50 MB. En teoría debería entrar en memoria sin problemas.

Lo que me llama la atención es que el error diga que es un problema de la pila.

¿Es que acaso pasas $buffer a través de una llamada a una función?

Sin más datos, yo sigo pensando que el límite está en los límites impuestos por el sistema operativo. Debes hablar con tu administrador del sistema y pedirle que aumente esos límites.

Mientras, podrías probar este programa, cambiando 'archivo_grande.dat' por el nombre de tu archivo:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl -C
  2.  
  3. open my $FILE, '<', 'archivo_grande.dat' or die "ERROR: No puedo abrir el archivo: $!\n";
  4. binmode $FILE                            or die "ERROR: No puedo pasar a modo binario: $!\n";
  5.  
  6. my $nbytes_leidos = read $FILE, my $buffer, 200_000_000;
  7.  
  8. close  $FILE                              or die "ERROR: No puedo cerrar el archivo: $!\n";
  9.  
  10. defined $nbytes_leidos                    or die "ERROR: No he leído el archivo: $!\n";
  11.  
  12. print "Número de bytes leídos: ", $nbytes_leidos,  "\n";
  13. print "Longitud del buffer:    ", length($buffer), "\n";
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4

Aunque... si repasas mi ulimit, yo tengo un límite de solo 8 MB, y puedo ejecutar programas muy grandes.

¿En qué sistema operativo estás? ¿Qué versión de Perl tienes?
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Abrir archivos binarios de tamaño de 50 megas con Perl

Notapor lobnomis » 2014-05-05 09:04 @419

¿Qué tal?

Hice la instalación de Perl en ambiente Windows 8 y me funciona muy bien el script de Perl con archivos grandes.

Esto lo ejecute en ambiente UNIX Perl 5.8.

Esto es lo que me salió al ejecutar el script que sugeriste:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
Número de bytes leídos: 28801230
Longitud del buffer:    28801230
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

Este es el script que me da problemas:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. $buffer   = "";
  2. $respaldo = $archivo . ".proc";
  3.  
  4. qx(mv $archivo $respaldo);
  5. open( FILE,   "<$respaldo" );
  6. open( SALIDA, ">>$archivo" );
  7. binmode(FILE);
  8. binmode(SALIDA);
  9. my $s = -s $respaldo;
  10. read( FILE, $buffer, $s );
  11. close(FILE);
  12. $i = -1;
  13.  
  14. @datos = split( //, $buffer );
  15. foreach (@datos) {
  16.     ++$i;
  17.     $byte = $_;
  18.     $dec  = hex( ord($_) );
  19.     if ( defined($indice) && $i == $indice ) {
  20.         open( BINARIO, "binario" );
  21.         binmode(BINARIO);
  22.         while (<BINARIO>) {
  23.             print SALIDA $_;
  24.         }
  25.         close(BINARIO);
  26.         next;
  27.     }
  28.     if ( $dec eq "297" ) {
  29.         $dec1 = hex( ord( $datos[ $i + 1 ] ) );
  30.         if ( $dec1 eq "88" ) {
  31.             $dec2 = hex( ord( $datos[ $i + 2 ] ) );
  32.             if ( $dec2 eq "1" ) {
  33.                 $dec3 = hex( ord( $datos[ $i + 3 ] ) );
  34.                 if ( $dec3 eq "1" ) {
  35.                     print SALIDA $byte;
  36.                     $indice = $i + 3;
  37.                 }
  38.                 else {
  39.                     print SALIDA $byte;
  40.                 }
  41.             }
  42.             else {
  43.                 print SALIDA $byte;
  44.             }
  45.         }
  46.         else {
  47.             print SALIDA $byte;
  48.         }
  49.     }
  50.     else {
  51.         print SALIDA $byte;
  52.     }
  53. }
  54. close(SALIDA);
  55. if ( !( defined($indice) ) ) {
  56.     print "El archivo $salida fue generado sin cambios.\n";
  57. }
  58. else {
  59.     print "El archivo $salida fue generado exitosamente.\n";
  60. }
  61. print "Fin.\n";
  62.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Gracias por el apoyo...
lobnomis
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2014-05-02 11:00 @500

Re: Abrir archivos binarios de tamaño de 50 megas con Perl

Notapor explorer » 2014-05-05 11:43 @530

El programa no tiene nada extraño, así que no veo qué puede pasar. La versión de Perl es muy vieja, eso sí, pero por lo demás, no veo nada raro.

Lo que sí veo son algunas cosas que te quiero comentar.
  • Puedes reducir las líneas 14 y 15 a una sola, para ver si ese es el problema: foreach my $byte (split //, $buffer) {
  • Si el archivo 'binario' tenemos que insertarle más de una vez, nos compensaría el leer al principio y meterlo en una variable escalar, para no tener que acceder a su archivo varias veces
  • $dec es un número, así que las comparaciones en los if se pueden hacer con '==' en lugar de con 'eq'
Esta es mi versión (no probada):
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. open my $BINARIO, '<', 'binario';
  2. binmode $BINARIO;
  3. read    $BINARIO, my $binario, -s 'binario';
  4. close   $BINARIO;
  5.  
  6. my $respaldo = "$archivo.proc";
  7. qx(mv $archivo $respaldo);
  8.  
  9. open my $FILE, '<', $respaldo;
  10. binmode $FILE;
  11. read    $FILE, my $buffer, -s $respaldo;
  12. close   $FILE;
  13.  
  14. open my $SALIDA, '>>', $archivo;
  15. binmode $SALIDA;
  16.  
  17. my $i = -1;
  18. my $indice;
  19.  
  20. foreach my $byte (split //, $buffer) {
  21.     ++$i;
  22.  
  23.     if ( defined($indice)  and  $i == $indice ) {
  24.         print $SALIDA $binario;
  25.         next;
  26.     }
  27.  
  28.     my $dec  = hex ord $byte;
  29.  
  30.     if ($dec == 297) {
  31.         my  $dec1              = hex ord $datos[$i + 1];
  32.         if ($dec1 == 88) {
  33.             my  $dec2          = hex ord $datos[$i + 2];
  34.             if ($dec2 == 1) {
  35.                 my  $dec3      = hex ord $datos[$i + 3];
  36.                 if ($dec3 == 1) {
  37.                     $indice = $i + 3;
  38.                 }
  39.             }
  40.         }
  41.     }
  42.  
  43.     print $SALIDA $byte;
  44. }
  45.  
  46. close $SALIDA;
  47.  
  48. if (! defined $indice) {
  49.     print "El archivo $salida fue generado sin cambios.\n";
  50. }
  51. else {
  52.     print "El archivo $salida fue generado exitosamente.\n";
  53. }
  54.  
  55. print "Fin.\n";
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Abrir archivos binarios de tamaño de 50 megas con Perl

Notapor lobnomis » 2014-05-05 15:15 @677

¿Qué tal?

Verifiqué el script, y lo acoplé para ejecutarlo con el file con el cual tiene problema pero sigue saliendo el problema de Out memory.

La ejecución:
Name "main::SALIDA" used only once: possible typo at procesasa_TAP.pl line 53.

Procesando ...
Out of memory!


¿Existe alguna forma de hacerle un trace y poder identificar en qué parte se genera el error?
lobnomis
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2014-05-02 11:00 @500

Re: Abrir archivos binarios de tamaño de 50 megas con Perl

Notapor explorer » 2014-05-05 17:43 @780

El error de SALIDA estaba en la línea 24. Ya está corregido. Faltaba ponerle un '$' delante para indicar que es una variable escalar.

Sobre el tema del trazado, una manera sería usando el depurador que trae el propio Perl.

Ejecútalo así:

perl -d procesasa_TAP.pl

Cuando salga el prompt '>', pulsas la tecla 'n' y le das a la tecla de Entrar. De esa manera, se habrá ejecutado la primera instrucción del programa. Las siguientes veces, te vale con pulsar la tecla Entrar.

El depurador va ejecutando línea por línea (mejor dicho, sentencia por sentencia. Algunas líneas tienen varias sentencias, aunque no lo parezcan). Tú sigue pulsando la tecla Entrar, hasta que falle, y así sabemos dónde está el fallo. Mejor dicho: dónde se supera la cantidad de memoria que el sistema nos permite.

Para salir del depurador, la tecla es 'q'. Puedes imprimir el contenido de variables con 'p' y mirar la estructura de variables más complejas con 'x' (que hace un Dump de la variable). La tecla 'h' muestra la ayuda.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Abrir archivos binarios de tamaño de 50 megas con Perl

Notapor lobnomis » 2014-05-06 08:59 @416

¿Qué tal?

Realicé el proceso del trazado:

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
main::(procesasa_TAP.pl:3):     $archivo=$ARGV[0];
  DB<1> n
main::(procesasa_TAP.pl:4):     $total=@ARGV;
  DB<1>
main::(procesasa_TAP.pl:5):     if($total != 1) {
  DB<1>
main::(procesasa_TAP.pl:9):     print "\nProcesando ...\n";
  DB<1>

Procesando ...
main::(procesasa_TAP.pl:10):    $bandera=0;
  DB<1>
main::(procesasa_TAP.pl:11):    if(-s "binario") {
  DB<1>
main::(procesasa_TAP.pl:12):            open(BIN, "binario");
  DB<1>
main::(procesasa_TAP.pl:13):            binmode(BIN);
  DB<1>
main::(procesasa_TAP.pl:14):            while(<BIN>) {
  DB<1>
main::(procesasa_TAP.pl:15):                    $dec=hex(ord($_));
  DB<1>
main::(procesasa_TAP.pl:16):                    if($dec eq "3") {
  DB<1>
main::(procesasa_TAP.pl:17):                            $bandera=1;
  DB<1>
main::(procesasa_TAP.pl:20):            close(BIN);
  DB<1>
main::(procesasa_TAP.pl:22):    if($bandera == 0) {
  DB<1>
main::(procesasa_TAP.pl:30):    open my $BINARIO, '<', 'binario';
  DB<1>
main::(procesasa_TAP.pl:31):    binmode $BINARIO;
  DB<1>
main::(procesasa_TAP.pl:32):    read    $BINARIO, my $binario, -s 'binario';
  DB<1>
main::(procesasa_TAP.pl:33):    close   $BINARIO;
  DB<1>
main::(procesasa_TAP.pl:35):    my $respaldo = "$archivo.proc";
  DB<1>
main::(procesasa_TAP.pl:37):    qx(mv $archivo $respaldo);
  DB<1>
main::(procesasa_TAP.pl:39):    open my $FILE, '<', $respaldo;
  DB<1>
main::(procesasa_TAP.pl:40):    binmode $FILE;
  DB<1>
main::(procesasa_TAP.pl:41):    read    $FILE, my $buffer, -s $respaldo;
  DB<1>
main::(procesasa_TAP.pl:42):    close   $FILE;
  DB<1>
main::(procesasa_TAP.pl:44):    open my $SALIDA, '>>', $archivo;
  DB<1>
main::(procesasa_TAP.pl:45):    binmode $SALIDA;
  DB<1>
main::(procesasa_TAP.pl:46):    my $i = -1;
  DB<1>
main::(procesasa_TAP.pl:47):    my $indice;
  DB<1>
main::(procesasa_TAP.pl:49):    foreach my $byte (split //, $buffer) {
  DB<1>
Out of memory!
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
lobnomis
Perlero nuevo
Perlero nuevo
 
Mensajes: 6
Registrado: 2014-05-02 11:00 @500

Re: Abrir archivos binarios de tamaño de 50 megas con Perl

Notapor explorer » 2014-05-06 10:00 @458

En efecto: no hay problema para leer el archivo a memoria, pero sí para desplegarlo en forma de lista de valores.

¿Qué versión de Perl es? Sabemos que es la v5.8, pero no la subversión. Ejecuta un

perl -V

y nos mandas del resultado.

Sospecho que tiene que ver con la versión de Perl. Si es eso, tendrás que actualizar Perl a algo más moderno (v5.8.0 es de hace doce años). Algunas versiones tenían problemas de reserva de memoria, y no conseguían reservar más de 1 GB.

Otra opción: reescribir el código para no tener que hacer lo del array.

Si el problema es acceder a tres bytes que están más allá del que estamos leyendo, hay dos opciones que se me ocurren:
  • leer cuatro bytes de cada vez, reposicionando el puntero de lectura con seek() en cada byte del archivo (siempre leemos el byte actual y los tres siguientes. Los bytes siguientes los podemos pasar a array con un split() como tienes ahora, o los sacamos de forma individual con substr()
  • leer el archivo byte a byte con read(), y cuando necesitamos leer los tres siguientes, primero recordamos la posición actual del puntero (con tell()) y luego vamos leyendo los bytes con sucesivos read(). Al final del primer if(), reposicionamos el puntero con seek().

También, lo que nos ayudaría, sería saber qué es lo que realmente hace este programa :)
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Siguiente

Volver a Bioinformática

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 0 invitados