OVH Cloud OVH Cloud

Segmentation fault et/ou blocage de la machine.

9 réponses
Avatar
Isammoc
J'ai une machine sous linux (Débian Sarge mise à jour tous les jours) et
je fais tourner un script perl toutes les heures (avec crontab). Bon,
jusqu'à la, pas grand chose d'interessant.

Mais le problème, c'est que pour un tableau de 200/300 individus, ca
passe, mais pour 500 et plus, le script me fait une segmentation fault ou
alors bloque complètement l'ordinateur (pas vraiment cool, lorsqu'il
s'agira d'un serveur)

Donc, mes questions:
Ai-je mal fait quelque chose dans mon script (cf plus bas)
Y a-t-il une limitation de perl? (pourtant mon script ne prend que 4.6%
de la mémoire, et pratiquement tout le CPU mais bon, c'est le seul
programme à tourner à ce moment là, donc je juge que c'est normal)
Est-ce que si je le compile (il parait qu'il y a des compilateurs perl)
le probleme sera résolu?


Merci d'avance.

Je passe les initialisations...

#####
# Chasse
#####
warn "début chasse";
my $chasseur;
my $proie;

# tableau des chasseurs
@chasseurs = ();
for ($i = 0; $i <= $#individus; $i++) {
if($individus[$i]->{'chasse'} >= 1) {
@chasseurs = (@chasseurs,$i);
}
}

while ($#chasseurs != -1) {
warn "".$#chasseurs + 1 ."/".$nbMaxChasseurs;

# choix d'un chasseur
$chasseur = $chasseurs[rand @chasseurs];

# tableau des proies
@proies = ();
for ($i = 0; $i <= $#individus; $i++) {
if ($individus[$i]->{'chasseable'} == 1 && $individus[$i]->
{'id'} != $individus[$chasseur]->{'id'} && @especes[$individus[$i]->
{'id'}]->{'M'} <= @especes[$individus[$chasseur]->{'id'}]->{'S'} &&
@especes[$individus[$i]->{'id'}]->{'M'} >= @especes[$individus
[$chasseur]->{'id'}]->{'I'}) {
@proies = (@proies, $i);
}
}

if ($#proies == -1) {
# bredouille
for ($i = 0; $i <= $#individus; $i++) {
if ($individus[$i]->{'id'} == $individus[$chasseur]->
{'id'}) {
$individus[$i]->{'chasse'} = 0;
if ($individus[$i]->{'Att'} == 0) {
# pas d'attaque faute de proies.
$especes[$individus[$chasseur]->{'id'}]->
{'nbNoAtt'}++;
}
}
}
} else {
# choix d'une proie
$proie = $proies[rand @proies];
$individus[$chasseur]->{'Att'}++;
$especes[$individus[$chasseur]->{'id'}]->{'Att'}++;
$especes[$individus[$proie]->{'id'}]->{'Def'}++;
$individus[$proie]->{'chasseable'} = 0;

# attaque d'une proie
if ((int(rand($especes[$individus[$chasseur]->{'id'}]->{'A'} +
$especes[$individus[$proie]->{'id'}]->{'D'}))+1) <= $especes[$individus
[$chasseur]->{'id'}]->{'A'}) {
# elle est mangée.
#on enleve la proie
$individus[$proie]->{'chasse'} = 0;
$individus[$proie]->{'mangé'} = 1;
$individus[$chasseur]->{'mange'} = 1;
$especes[$individus[$proie]->{'id'}]->{'population'}--;
warn "avant INSERT";
$dbh->do('INSERT INTO PP VALUES (?,?)', undef, ($especes
[$individus[$chasseur]->{'id'}]->{'id'},$especes[$individus[$proie]->
{'id'}]->{'id'}));
warn "apres INSERT";
# on enleve le chasseur
#$individus[$chasseur]->{'chasse'} = 0;
} else {
# elle est sauve.
$individus[$chasseur]->{'chasse'}--;

}

}
warn "avant table de chasseurs";
# tableau des chasseurs
@chasseurs = ();
for ($i = 0; $i <= $#individus; $i++) {
if($individus[$i]->{'chasse'} >= 1) {
@chasseurs = (@chasseurs,$i);
}
}
warn "apres tableau de chasseurs";
}
warn "fin de chasse";


--
Isammoc

9 réponses

Avatar
Patrick Mevzek
Mais le problème, c'est que pour un tableau de 200/300 individus, ca
passe, mais pour 500 et plus, le script me fait une segmentation fault ou
alors bloque complètement l'ordinateur (pas vraiment cool, lorsqu'il
s'agira d'un serveur)


Relativement surprenant. A moins que vous réussissiez à remplir
complétement toute la mémoire vive.

Donc, mes questions:
Ai-je mal fait quelque chose dans mon script (cf plus bas) Y a-t-il une
limitation de perl? (pourtant mon script ne prend que 4.6% de la
mémoire, et pratiquement tout le CPU mais bon, c'est le seul programme
à tourner à ce moment là, donc je juge que c'est normal) Est-ce que
si je le compile (il parait qu'il y a des compilateurs perl) le probleme
sera résolu?


Personnellement, je vous recommanderai déjà une écriture plus
perlienne, ca fera quelque chose de bien plus clair.

Exemple:

# tableau des chasseurs
@chasseurs = ();
for ($i = 0; $i <= $#individus; $i++) {
if($individus[$i]->{'chasse'} >= 1) {
@chasseurs = (@chasseurs,$i);
}
}


Deviendrait:

my @chasseurs=grep { $individus[$_]->{chasse} >=1 } (0..$#individus)

ou si vous voulez garder les éléments et pas leur rang
(ce qui semble encore mieux IMNSHO) :

my @chasseurs=grep { $_->{chasse} >= 1 } @individus;

Quasimment tout votre programme est simplifiable de la sorte.

Evitez aussi les :
@proies = (@proies, $i);
puisque
push @proies,$i
suffit et évite d'accabler la mémoire.

--
Patrick Mevzek . . . . . . Dot and Co (Paris, France)
<http://www.dotandco.net/> <http://www.dotandco.com/>
Dépêches sur le nommage <news://news.dotandco.net/dotandco.info.news>

Avatar
Laurent Wacrenier
Patrick Mevzek écrit:
Personnellement, je vous recommanderai déjà une écriture plus
perlienne, ca fera quelque chose de bien plus clair.

Exemple:


Autre exemple,
"espace" et "id" ne sont utilisés que dans cette forme là.

$especes[$individus[$chasseur]->{'id'}]

Ce serait plus clair de virer "id" et de mettre une clef "espece" à la
place, pour avoir.

$individus[$chasseur]->{espece}

(affecté à feu $especes[$individus[$chasseur]->{'id'}] )


La grosse boucle est loin d'être compréensible.
Utiliser des map, des grep, des pop, des push, des noms de clef
parlantes et des commentaires aiderait.

Plutôt que

for ($i = 0; $i <= $#individus; $i++) {
if ($individus[$i]->{'chasseable'} == 1 && $individus[$i]->
{'id'} != $individus[$chasseur]->{'id'} && @especes[$individus[$i]->
{'id'}]->{'M'} <= @especes[$individus[$chasseur]->{'id'}]->{'S'} &&
@especes[$individus[$i]->{'id'}]->{'M'} >= @especes[$individus
[$chasseur]->{'id'}]->{'I'}) {
@proies = (@proies, $i);
}

Ce serait plus lisible d'organiser la structure pour avoir

for my $i (@individus) {
if ($i->{chasseable} &&
$i->{espece} == $chasseur->{espece} &&
$i->{espece}->{M} <= $chasseur->{espece}->{S} &&
$i->{espece}->{M} >= $chasseur->{espece}->{I}) {
push @proies, $i;
}
}

(j'ai pas compris les @especes[$individus[$i]->{'id'}]->{'M'})

Mais ça serait mieux avec un grep et avec d'autres clefs que M, S et I.


Programmé orienté objet, ça serait encore mieux.

Avatar
Isammoc
Personnellement, je vous recommanderai déjà une écriture plus
perlienne, ca fera quelque chose de bien plus clair.



J'avoue que j'ai du mal à ce niveau la.

Exemple:


Autre exemple,
"espace" et "id" ne sont utilisés que dans cette forme là.

$especes[$individus[$chasseur]->{'id'}]


especes est un tableau d'objets.
Pour ne pas encombrer la mémoire, je pensais ne prendre que l'index du
tableau @especes dans le champ id des éléments du tableau @individus.

Ce serait plus clair de virer "id" et de mettre une clef "espece" à la
place, pour avoir.

$individus[$chasseur]->{espece}


Ce qui fait que pour chaque espèce, il y aurait l'objet? C'est pas plus
gourmand en mémoire?

La grosse boucle est loin d'être compréensible.
Utiliser des map, des grep, des pop, des push, des noms de clef
parlantes et des commentaires aiderait.


J'avoue ne pas savoir utiliser les map et les grep.
Je pensais que les push et @a = (@a,$i) étaient équivalents.
Les noms de clefs sont parlantes à mon humble avis.
Etant donné que:
@especes est un tableau d'objets de type Espece;
@individus est un tableau d'éléments complexes {} dont la clef 'id'
correspond à l'index du tableau @especes;
@chasseurs est un tableau des index du tableau @individus qui peuvent
chasser.
@proies meme genre que @chasseurs, mais pour les proies possible du
chasseur sélectionné.

Plutôt que

for ($i = 0; $i <= $#individus; $i++) {
if ($individus[$i]->{'chasseable'} == 1 &&
$individus[$i]->
{'id'} != $individus[$chasseur]->{'id'} && @especes[$individus[$i]->
{'id'}]->{'M'} <= @especes[$individus[$chasseur]->{'id'}]->{'S'} &&
@especes[$individus[$i]->{'id'}]->{'M'} >= @especes[$individus
[$chasseur]->{'id'}]->{'I'}) {
@proies = (@proies, $i);
}

Ce serait plus lisible d'organiser la structure pour avoir

for my $i (@individus) {
if ($i->{chasseable} &&
$i->{espece} == $chasseur->{espece} &&
$i->{espece}->{M} <= $chasseur->{espece}->{S} &&
$i->{espece}->{M} >= $chasseur->{espece}->{I}) {
push @proies, $i;
}
}

(j'ai pas compris les @especes[$individus[$i]->{'id'}]->{'M'})


M est une caractéristique (métabolisme, ou masse). Vu que chaque individu
de la meme espece a le meme metabolisme, pas besoin de faire un champ M
dans individus, non?

Mais ça serait mieux avec un grep et avec d'autres clefs que M, S et
I.


M métabolisme
I inférieur
S supérieur

Programmé orienté objet, ça serait encore mieux.


Je vote pour... Espece et Individu sont des objets.

un début de site lié à ce projet: www.isammoc.net/predator


Avatar
Laurent Wacrenier
Isammoc écrit:
Autre exemple,
"espace" et "id" ne sont utilisés que dans cette forme là.

$especes[$individus[$chasseur]->{'id'}]


especes est un tableau d'objets.
Pour ne pas encombrer la mémoire, je pensais ne prendre que l'index du
tableau @especes dans le champ id des éléments du tableau @individus.


Si c'est un tableau de références, ce sont les références qui sont
affectées.

Ce serait plus clair de virer "id" et de mettre une clef "espece" à la
place, pour avoir.

$individus[$chasseur]->{espece}


Ce qui fait que pour chaque espèce, il y aurait l'objet? C'est pas plus
gourmand en mémoire?


Non, il y aurait une référence à l'objet (et non pas l'objet lui
même), plutôt qu'un scalaire.

La grosse boucle est loin d'être compréensible.
Utiliser des map, des grep, des pop, des push, des noms de clef
parlantes et des commentaires aiderait.


J'avoue ne pas savoir utiliser les map et les grep.
Je pensais que les push et @a = (@a,$i) étaient équivalents.


Sémantiquement, oui. Mais push ajoute un élément à une liste ce qui
est peu coûteux, alors que @a = (@a, $i) crée une nouvelle liste et
l'affecte.

Les noms de clefs sont parlantes à mon humble avis.
Etant donné que:
@especes est un tableau d'objets de type Espece;
@individus est un tableau d'éléments complexes {} dont la clef 'id'
correspond à l'index du tableau @especes;


@individu devrait être une liste de référence à des hash, plutôt
qu'une liste d'index à des références de hash.

@chasseurs est un tableau des index du tableau @individus qui peuvent
chasser.
@proies meme genre que @chasseurs, mais pour les proies possible du
chasseur sélectionné.

Plutôt que

for ($i = 0; $i <= $#individus; $i++) {
if ($individus[$i]->{'chasseable'} == 1 &&
$individus[$i]->
{'id'} != $individus[$chasseur]->{'id'} && @especes[$individus[$i]->
{'id'}]->{'M'} <= @especes[$individus[$chasseur]->{'id'}]->{'S'} &&
@especes[$individus[$i]->{'id'}]->{'M'} >= @especes[$individus
[$chasseur]->{'id'}]->{'I'}) {
@proies = (@proies, $i);
}

Ce serait plus lisible d'organiser la structure pour avoir

for my $i (@individus) {
if ($i->{chasseable} &&
$i->{espece} == $chasseur->{espece} &&
$i->{espece}->{M} <= $chasseur->{espece}->{S} &&
$i->{espece}->{M} >= $chasseur->{espece}->{I}) {
push @proies, $i;
}
}

(j'ai pas compris les @especes[$individus[$i]->{'id'}]->{'M'})


M est une caractéristique (métabolisme, ou masse). Vu que chaque individu
de la meme espece a le meme metabolisme, pas besoin de faire un champ M
dans individus, non?


Ce que je n'ai pas compris, c'est le @XXX[...]->{YYY}.
Ce ne serait pas plutôt
$XXX[...]->{YYY}


Mais ça serait mieux avec un grep et avec d'autres clefs que M, S et
I.


M métabolisme
I inférieur
S supérieur


Autant utiliser X->{metabolisme}, etc.

Programmé orienté objet, ça serait encore mieux.


Je vote pour... Espece et Individu sont des objets.

un début de site lié à ce projet: www.isammoc.net/predator


ça permetrait d'avoir une écriture plus aérée, par exemple :

my $e1 = new espece { sup => 10, inf => 0, meta => 5, chasseur => 1 };
my $e2 = new espece { sup => 30, inf => 0, meta => 5 };

my @population;
# ajoute 10 individus de l'espece e1
push @population, new individu $e1 for (1..10);
# ajoute 20 individus de l'espece e2
push @population, new individu $e2 for (1..20);

@chasseurs = grep { $_->chasseur } @population;
while (@chasseur) {
my $c = $chasseurs[rand @chasseurs];

@proies = grep { $_->chassable &&
$_->espece != $c->espece &&
$_->meta <= $c->sup &&
$_->meta >= $c->inf } @population;

unless(@proies) {
#bredouille
...
for (grep { $_->espece = $c->espece } @population) {
$_->chasse(0);
$c->espece->{ nbNoAtt }++ unless $_->att;
}
}
etc...
}

Avec des méthodes :

package individu;
sub sup { $_[0]->{espece}->{sup}; }
etc..


Avatar
Isammoc
Si c'est un tableau de références, ce sont les références qui sont
affectées.


je note.

Non, il y aurait une référence à l'objet (et non pas l'objet lui
même), plutôt qu'un scalaire.


comme en C/C++...

Sémantiquement, oui. Mais push ajoute un élément à une liste ce qui
est peu coûteux, alors que @a = (@a, $i) crée une nouvelle liste et
l'affecte.


En effet, lorsque j'ai remplacé tous les @a (@a,$i) par des push, le
script tourne sans probleme (pour l'instant).

@individu devrait être une liste de référence à des hash, plutôt
qu'une liste d'index à des références de hash.


Vu que c'est bien la référence qui est stockée dans la liste, ca va etre
possible (c'est ce que j'avais fait au départ, mais ce ne marchait pas, à
cause des push)

Ce que je n'ai pas compris, c'est le @XXX[...]->{YYY}.
Ce ne serait pas plutôt
$XXX[...]->{YYY}


Euh, si il y a des chances... Vais vérifier ca de suite.
[2 minutes plus tard] Ca y est.. j'ai changé cela

M métabolisme
I inférieur
S supérieur


Autant utiliser X->{metabolisme}, etc.


Disons que c'est autant ca de moins à taper, et que c'est vraiment qqch
que j'utilise tout le temps... Donc c'est assez compréhensible.
Meme dans les règles, j'utilise "votre espèce peut chasser des individus
d'autres espèces dont la caractéristique M est comprise entre les
caractéristiques I et S de votre espèce."

ça permetrait d'avoir une écriture plus aérée, par exemple :

my $e1 = new espece { sup => 10, inf => 0, meta => 5, chasseur => 1 };
my $e2 = new espece { sup => 30, inf => 0, meta => 5 };


pour l'instant:
my $espece = new Espece(id);
et ca récupère directement l'espèce depuis la base de donnée...

my @population;
# ajoute 10 individus de l'espece e1
push @population, new individu $e1 for (1..10);
# ajoute 20 individus de l'espece e2
push @population, new individu $e2 for (1..20);


Ca, je ne pense pas que ce soit possible.... Vu que les individus
diffèrent par le fait qu'ils soient chassables ou non, et le nombre de
chasse qu'ils peuvent effectuer... Mais je retiens la syntaxe pour
d'autres cas.

@chasseurs = grep { $_->chasseur } @population;
while (@chasseur) {
my $c = $chasseurs[rand @chasseurs];

@proies = grep { $_->chassable &&
$_->espece != $c->espece &&
$_->meta <= $c->sup &&
$_->meta >= $c->inf } @population;

unless(@proies) {
#bredouille
...
for (grep { $_->espece = $c->espece } @population) {
$_->chasse(0);
$c->espece->{ nbNoAtt }++ unless $_->att;
}
}
etc...
}



joliment fait... C'est clair que c'est plus clair ;-P


Avec des méthodes :

package individu;
sub sup { $_[0]->{espece}->{sup}; }
etc..


Pas compris celui la.
(j'ai compris que c'était la définition d'une méthode sup pour l'objet de
type individu mais je ne vois pas ce qu'elle fait à l'espece du premier
parametre).

--
Isammoc


Avatar
Laurent Wacrenier
fIsammoc écrit:
Avec des méthodes :

package individu;
sub sup { $_[0]->{espece}->{sup}; }
etc..


Pas compris celui la.
(j'ai compris que c'était la définition d'une méthode sup pour l'objet de
type individu mais je ne vois pas ce qu'elle fait à l'espece du premier
parametre).


Il va chercher la valeur de la clef "sup".

C'est encore plus drole avec "overload" (mais pas forcement plus
clair si on en abuse) :

#! /usr/bin/perl

package Espece;
use overload
'""' => sub { $_[0]->{name} },
'<=>' => sub { $_[0]->{prop}->{force} <=> $_[1]->{prop}->{force} };

sub new {
my $class = shift;
my $name = shift;
my $properties = shift;
my $self = { prop => $properties, name => $name };
return bless $self, $class;
}

sub prop { $_[0]->{prop}->{$_[1]} }

package Individu;
use overload
'""' => sub { $_[0]->{name} };

sub new {
my $class = shift;
my $name = shift;
my $espece = shift;
my $self = { espece => $espece, name => $name };
return bless $self, $class;
}


sub espece { $_[0]->{espece} }
sub prop { $_[0]->{espece}->prop($_[1]) }

package main;

my $e1 = new Espece "lapin", { oreilles => 2, force => 1 };
my $i1 = new Individu "Jeannot", $e1;

print $i1, " le ", $i1->espece, " a ",
$i1->prop("oreilles"), " oreillesn";

my $e2 = new Espece "renard", { force => 10 };

if ($e2 > $e1) {
print "Un $e2 est plus fort qu'un $e1n";
}


Avatar
Isammoc
package individu;
sub sup { $_[0]->{espece}->{sup}; }
etc..



Il va chercher la valeur de la clef "sup".


C'est pas plutot
$_[0]->{'espece'}->{'sup'};
?

C'est encore plus drole avec "overload" (mais pas forcement plus
clair si on en abuse) :


[snip code]

Ici, ca permet de faire l'équivalent d'une méthode toString en java... non?

--
Isammoc



Avatar
Patrick Mevzek
package individu;
sub sup { $_[0]->{espece}->{sup}; }
etc..



Il va chercher la valeur de la clef "sup".


C'est pas plutot
$_[0]->{'espece'}->{'sup'};


Il n'est pas obligatoire d'entourer les clefs de hash par des guillemets
(simples ou doubles d'ailleurs), quand il n'y a pas d'ambiguité (style
espace ou autres caractères du genre)

C'est encore plus drole avec "overload" (mais pas forcement plus
clair si on en abuse) :


[snip code]

Ici, ca permet de faire l'équivalent d'une méthode toString en java... non?


Pas tout à fait, mais je laisse Laurent prolonger son idée :-)

--
Patrick Mevzek . . . . . . Dot and Co (Paris, France)
<http://www.dotandco.net/> <http://www.dotandco.com/>
Dépêches sur le nommage <news://news.dotandco.net/dotandco.info.news>




Avatar
Laurent Wacrenier
Isammoc écrit:
sub sup { $_[0]->{espece}->{sup}; }
etc..



Il va chercher la valeur de la clef "sup".


C'est pas plutot
$_[0]->{'espece'}->{'sup'};
?


Oui si on aime les lignes longues.

C'est encore plus drole avec "overload" (mais pas forcement plus
clair si on en abuse) :


[snip code]

Ici, ca permet de faire l'équivalent d'une méthode toString en java... non?


connait pas java.