Caribensila
Messages postés2527Date d'inscriptionjeudi 15 janvier 2004StatutMembreDernière intervention16 octobre 2019
-
9 avril 2011 à 18:47
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 2016
-
12 avril 2011 à 22:03
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 201610 12 avril 2011 à 22:03
Salut ManChesTer, en fait seul la partie qui prend du temps est optimisée. Le reste comme le chargement de l'image ... bon. Mais on peut cdertainement l'optimiser, en effet comme tu le montres dans ton commentaire.
Et un try, oui, ça en a pas l'air mais ça ne prend pas plus de temps d'exécuter du code protégé par un try - il y a juste un flag quelque part qui dit au compilateur que tel code doit s'éxécuter à tout prix ou que telle exception doit être redirigée.
Cordialement, Bacterius !
cs_ManChesTer
Messages postés374Date d'inscriptionvendredi 20 octobre 2000StatutModérateurDernière intervention15 janvier 2021 11 avril 2011 à 15:11
Salut Bacterius,
Bon code mais il est encore possible de l'optimisée
par exemple dans main :
# JPG := TJPEGImage.Create;
# JPG.LoadFromFile('Image.jpg');
# Bmp := TBitmap.Create;
# Bmp.Assign(JPG);
# Bmp.PixelFormat := pf32bit;
# Bmp2 := TBitmap.Create;
# JPG.Free;
me fais des frissons dans le dos,
un with TJPEGImage.Create do
...
dans la lib le try , c'est optimisé ca un try ?
Bon Coding...
ManChesTer.
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 201610 10 avril 2011 à 22:57
Admettons :p
"Mais, de toute façon, plus la capacité des RAMs augmente chez les utilisateurs, plus les programmeurs les remplissent. C'est bien connu ! lol"
Eh oui, je sais même pas quoi faire des mes 4Go, j'ai l'impression de gaspiller :(
Cordialement, Bacterius !
Caribensila
Messages postés2527Date d'inscriptionjeudi 15 janvier 2004StatutMembreDernière intervention16 octobre 201918 10 avril 2011 à 22:53
Quand tu programmeras un dessin animé avec quelques milliers de Bitmaps, tu changeras peut-être d'avis. :)
Mais, de toute façon, plus la capacité des RAMs augmente chez les utilisateurs, plus les programmeurs les remplissent. C'est bien connu ! lol
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 201610 10 avril 2011 à 22:47
Merci, ça sera bien utile pour le pf24bit ! :) Mais bon il reste un petit problème - les PC d'aujourd'hui sont tellement rapides que la différence entre 24 et 32 bits est négligeable - en fait le 32 bits irait plus vite à cause justement de l'alignement mémoire.
Je vais l'ajouter comme exercice et pour compatibilité, mais ça n'a que peu d'intérêt au niveau pratique (tous les bitmaps sont en 32 bits de nos jours).
Cordialement, Bacterius !
Caribensila
Messages postés2527Date d'inscriptionjeudi 15 janvier 2004StatutMembreDernière intervention16 octobre 201918 10 avril 2011 à 22:38
Si tu te lances dans le pf24bit, je te file un petit truc qui te sera bien utile.
Ca calcule le nombre de Bytes par ligne de mémoire :
« ...Et c'est la classe d'appeller VirtualAlloc »
Oui , c'est sûr ! :)
Tu me tentes...
Je vais me lancer ! ;)
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 201610 10 avril 2011 à 22:19
"Et ton algo, en fin de ligne, ajoutera 18 aux Pointeurs pour sauter 1 ligne ( Inc(S1, W); Inc(S2, W); ) alors qu'il devrait ajouter 20 ==> foutoir assuré !"
C'est vrai. Il y a moyen de corriger ça en remplacant les Inc plus haut par des incrémentations arithmétiques prenant en compte l'alignement mémoire (à coup de mod - enfin de and pour la performance). Je vais creuser ça.
"Non ! Ce n'est pas PTR_Downsample qui est appelé plusieurs fois (ça, c'est normal), c'est bien Downsample !
Pour t'en convaincre, mets un simple 'Beep' au début de ta fonction Downsample. Tu entendras le concert ! :)"
Ah ?? Ca ce n'est pas normal, je vais regarder ça, merci Cari :p
"Je n'ai jamais utilisé VirtualAlloc, et je pense qu'il vaut mieux laisser le Système gérer la mémoire virtuelle. Il se débrouille très bien avec tout ce bazar."
C'est pourtant bien utile quand on travaille avec des fichiers sans passer par le cache système :'( Et c'est la classe d'appeller VirtualAlloc :p
"J'ai pourtant déjà optimisé du code pour bien moins que ça ! ;)"
Héhé oui, il est vrai que la fonction PTR_Downsample pourrait être rendue plus complexe pour gérer les réductions par 2, 4, 8, etc... en un seul coup. Mais bon, je préférais laisser le code simple pour bien qu'on comprenne le truc des pointeurs.
Cordialement, Bacterius !
Caribensila
Messages postés2527Date d'inscriptionjeudi 15 janvier 2004StatutMembreDernière intervention16 octobre 201918 10 avril 2011 à 19:14
J'oubliais...
« Mais un point intéressant est que le coût de la fonction décroît exponentiellement à chaque appel, donc finalement appeller 4 fois Downsample ne serait que ~1.5 plus lent que de l'appeler une fois. »
J'ai pourtant déjà optimisé du code pour bien moins que ça ! ;)
Caribensila
Messages postés2527Date d'inscriptionjeudi 15 janvier 2004StatutMembreDernière intervention16 octobre 201918 10 avril 2011 à 18:54
« Pour le pf24bit, ce n'est pas vraiment un problème... »
Ce ne sera pas un problème à condition que tu ajoutes une nouvelle limitation. C'est à dire qu'il faudra des bitmaps dont la largeur est multiple de 4, sinon tu auras des problèmes d'alignement de fin de ligne.
Un petit exemple pour te faire comprendre :
Soit un pf24bit de 6 pixels de large.
Il a besoin de 3x6 = 18 Bytes par ligne pour coder ses 6 TRGBTriples.
Or la mémoire est alignée sur des Longwords de 4 bytes.
En mémoire, ce Bitmap occupera donc une largeur de 5 Longwords, soit 20 Bytes (et non pas 18 !).
Et ton algo, en fin de ligne, ajoutera 18 aux Pointeurs pour sauter 1 ligne ( Inc(S1, W); Inc(S2, W); ) alors qu'il devrait ajouter 20 ==> foutoir assuré !
« En revanche, le simple Stretch de Delphi n'utilise pas le système de moyenne de pixels... »
Au temps pour moi. Tu as raison, ton algo est de meilleur qualité.
« C'est normal pour TrackbarChange... »
Non ! Ce n'est pas PTR_Downsample qui est appelé plusieurs fois (ça, c'est normal), c'est bien Downsample !
Pour t'en convaincre, mets un simple 'Beep' au début de ta fonction Downsample. Tu entendras le concert ! :)
« Serait-il plus intéressant de comparer ma fonction "simple" à une autre fonction identique... »
Le problème est qu'il n'existe pas de fonctions Stretch avec autant de limitations. Une "vraie" comparaison est donc impossible.
Quant à comparer la méthode des pointeur avec Get/SetDIBits, ça a déjà été fait et la palme revient à la méthode des pointeurs.
« saurais-tu pourquoi appeller VirtualFree avec MEM_DECOMMIT ou MEM_RELEASE après un appel à VirtualAlloc... »
Je n'ai jamais utilisé VirtualAlloc, et je pense qu'il vaut mieux laisser le Système gérer la mémoire virtuelle. Il se débrouille très bien avec tout ce bazar.
Bacterius
Messages postés3792Date d'inscriptionsamedi 22 décembre 2007StatutMembreDernière intervention 3 juin 201610 10 avril 2011 à 02:44
@Beckerich : super ! j'étais pas sûr avec tous ces pointeurs ...
@Caribensila : c'est vrai. Pour le pf24bit, ce n'est pas vraiment un problème à vrai dire, il suffit de changer le contenu des pointeurs et les mathématiques dans la boucle. Il n'y aurait pas de différence de performance importante.
Pour agrandir, c'est vrai, mais il ne faut pas oublier que les fonctions citées plus haut prennent un temps négligeable pour décider si il faut agrandir ou non, donc niveau performances ça n'a aucune importance. Niveau fonctionnalité, je te l'accorde. Pour tous les facteurs, effectivement, je te l'accorde, c'était un peu bas de ma part.
En revanche, le simple Stretch de Delphi n'utilise pas le système de moyenne de pixels, il prend simplement le pixel le plus proche. Donc si tu essayes de faire ça, dans les mêmes conditions, avec le Stretch de Delphi, tu verras que ça sera pas la même qualité (en tout cas dans Delphi 6 et 7, ça a peut-être changé dans les versions ultérieures).
C'est normal pour TrackbarChange, Downsample réduit l'image d'un facteur de deux, on l'appelle plusieurs fois pour obtenir une réduction plus importante. C'est voulu. Mais un point intéressant est que le coût de la fonction décroît exponentiellement à chaque appel, donc finalement appeller 4 fois Downsample ne serait que ~1.5 plus lent que de l'appeler une fois. Si ça avait été 4 fois plus lent j'aurai fait différemment.
Et oui je reconnais que ma clause try/except n'est pas terrible :( Mais bon, qui a des erreurs EOutOfMemory de nos jours :p
Merci pour tes remarques. Je vais particulièrement me pencher sur le problème du GetMem afin de corriger ça.
Serait-il plus intéressant de comparer ma fonction "simple" à une autre fonction identique, avec les mêmes conditions, mais utilisant Pixels par exemple ou Get/SetDIBits ? Ce serait alors honnête (je crois)
Cordialement, Bacterius !
PS : saurais-tu pourquoi appeller VirtualFree avec MEM_DECOMMIT ou MEM_RELEASE après un appel à VirtualAlloc avec MEM_COMMIT ne libère pas la mémoire correctement ? J'avais en tête d'utiliser ces fonctions pour obtenir une plage mémoire alignée pour que le CopyMemory aille plus vite, mais la mémoire ne se libérait pas proprement.
beckerich
Messages postés302Date d'inscriptionjeudi 29 septembre 2005StatutMembreDernière intervention17 septembre 20132 9 avril 2011 à 20:12
Bonsoir,
le code fonctionne sans modif sous delphi2010. Luc.
Caribensila
Messages postés2527Date d'inscriptionjeudi 15 janvier 2004StatutMembreDernière intervention16 octobre 201918 9 avril 2011 à 18:47
Salut,
Ton bench n'est pas très honnête car tu compares ta fonction à des fonctions qui font bien plus de choses. C'est heureux que tu sois plus rapide dans ces conditions !
Si ta fonction devait aussi pouvoir
- agrandir
- traiter le pf24bit et autres formats
- accepter n'importe quelles largeurs de bitmap
- s'adapter à tous les facteurs d'agrandissement, même non entiers
- et j'en passe,
je te fiche mon billet que tu n'obtiendrais pas le même classement de performances.
Quand à la qualité, essaie d'utiliser le simple Stretch de Delphi dans les mêmes conditions, c'est à dire 1 bitmaps pf32bit de largeur et hauteur paires et avec un facteur de réduction de 4, 16, 64, etc... , je serais étonné que tu n'obtiennes pas exactement la même qualité.
TrackbarChange appelle 4 fois la fonction Downsample pour une réduction. Y'a quelque chose qui ne colle pas.
Ton GetMem(D, Q) est placé après le try. Si ton GetMem échoue, FreeMem est quand même appelé !
Sinon, c'est pas mal pour montrer l'utilisation des pointeurs.
12 avril 2011 à 22:03
Et un try, oui, ça en a pas l'air mais ça ne prend pas plus de temps d'exécuter du code protégé par un try - il y a juste un flag quelque part qui dit au compilateur que tel code doit s'éxécuter à tout prix ou que telle exception doit être redirigée.
Cordialement, Bacterius !
11 avril 2011 à 15:11
Bon code mais il est encore possible de l'optimisée
par exemple dans main :
# JPG := TJPEGImage.Create;
# JPG.LoadFromFile('Image.jpg');
# Bmp := TBitmap.Create;
# Bmp.Assign(JPG);
# Bmp.PixelFormat := pf32bit;
# Bmp2 := TBitmap.Create;
# JPG.Free;
me fais des frissons dans le dos,
un with TJPEGImage.Create do
...
dans la lib le try , c'est optimisé ca un try ?
Bon Coding...
ManChesTer.
10 avril 2011 à 22:57
"Mais, de toute façon, plus la capacité des RAMs augmente chez les utilisateurs, plus les programmeurs les remplissent. C'est bien connu ! lol"
Eh oui, je sais même pas quoi faire des mes 4Go, j'ai l'impression de gaspiller :(
Cordialement, Bacterius !
10 avril 2011 à 22:53
Mais, de toute façon, plus la capacité des RAMs augmente chez les utilisateurs, plus les programmeurs les remplissent. C'est bien connu ! lol
10 avril 2011 à 22:47
Je vais l'ajouter comme exercice et pour compatibilité, mais ça n'a que peu d'intérêt au niveau pratique (tous les bitmaps sont en 32 bits de nos jours).
Cordialement, Bacterius !
10 avril 2011 à 22:38
Ca calcule le nombre de Bytes par ligne de mémoire :
MemBytePerLine := (((BMP.Width * BytePerPix shl 3) + 31) and -31) shr 3;
« ...Et c'est la classe d'appeller VirtualAlloc »
Oui , c'est sûr ! :)
Tu me tentes...
Je vais me lancer ! ;)
10 avril 2011 à 22:19
C'est vrai. Il y a moyen de corriger ça en remplacant les Inc plus haut par des incrémentations arithmétiques prenant en compte l'alignement mémoire (à coup de mod - enfin de and pour la performance). Je vais creuser ça.
"Non ! Ce n'est pas PTR_Downsample qui est appelé plusieurs fois (ça, c'est normal), c'est bien Downsample !
Pour t'en convaincre, mets un simple 'Beep' au début de ta fonction Downsample. Tu entendras le concert ! :)"
Ah ?? Ca ce n'est pas normal, je vais regarder ça, merci Cari :p
"Je n'ai jamais utilisé VirtualAlloc, et je pense qu'il vaut mieux laisser le Système gérer la mémoire virtuelle. Il se débrouille très bien avec tout ce bazar."
C'est pourtant bien utile quand on travaille avec des fichiers sans passer par le cache système :'( Et c'est la classe d'appeller VirtualAlloc :p
"J'ai pourtant déjà optimisé du code pour bien moins que ça ! ;)"
Héhé oui, il est vrai que la fonction PTR_Downsample pourrait être rendue plus complexe pour gérer les réductions par 2, 4, 8, etc... en un seul coup. Mais bon, je préférais laisser le code simple pour bien qu'on comprenne le truc des pointeurs.
Cordialement, Bacterius !
10 avril 2011 à 19:14
« Mais un point intéressant est que le coût de la fonction décroît exponentiellement à chaque appel, donc finalement appeller 4 fois Downsample ne serait que ~1.5 plus lent que de l'appeler une fois. »
J'ai pourtant déjà optimisé du code pour bien moins que ça ! ;)
10 avril 2011 à 18:54
Ce ne sera pas un problème à condition que tu ajoutes une nouvelle limitation. C'est à dire qu'il faudra des bitmaps dont la largeur est multiple de 4, sinon tu auras des problèmes d'alignement de fin de ligne.
Un petit exemple pour te faire comprendre :
Soit un pf24bit de 6 pixels de large.
Il a besoin de 3x6 = 18 Bytes par ligne pour coder ses 6 TRGBTriples.
Or la mémoire est alignée sur des Longwords de 4 bytes.
En mémoire, ce Bitmap occupera donc une largeur de 5 Longwords, soit 20 Bytes (et non pas 18 !).
Et ton algo, en fin de ligne, ajoutera 18 aux Pointeurs pour sauter 1 ligne ( Inc(S1, W); Inc(S2, W); ) alors qu'il devrait ajouter 20 ==> foutoir assuré !
« En revanche, le simple Stretch de Delphi n'utilise pas le système de moyenne de pixels... »
Au temps pour moi. Tu as raison, ton algo est de meilleur qualité.
« C'est normal pour TrackbarChange... »
Non ! Ce n'est pas PTR_Downsample qui est appelé plusieurs fois (ça, c'est normal), c'est bien Downsample !
Pour t'en convaincre, mets un simple 'Beep' au début de ta fonction Downsample. Tu entendras le concert ! :)
« Serait-il plus intéressant de comparer ma fonction "simple" à une autre fonction identique... »
Le problème est qu'il n'existe pas de fonctions Stretch avec autant de limitations. Une "vraie" comparaison est donc impossible.
Quant à comparer la méthode des pointeur avec Get/SetDIBits, ça a déjà été fait et la palme revient à la méthode des pointeurs.
« saurais-tu pourquoi appeller VirtualFree avec MEM_DECOMMIT ou MEM_RELEASE après un appel à VirtualAlloc... »
Je n'ai jamais utilisé VirtualAlloc, et je pense qu'il vaut mieux laisser le Système gérer la mémoire virtuelle. Il se débrouille très bien avec tout ce bazar.
10 avril 2011 à 02:44
@Caribensila : c'est vrai. Pour le pf24bit, ce n'est pas vraiment un problème à vrai dire, il suffit de changer le contenu des pointeurs et les mathématiques dans la boucle. Il n'y aurait pas de différence de performance importante.
Pour agrandir, c'est vrai, mais il ne faut pas oublier que les fonctions citées plus haut prennent un temps négligeable pour décider si il faut agrandir ou non, donc niveau performances ça n'a aucune importance. Niveau fonctionnalité, je te l'accorde. Pour tous les facteurs, effectivement, je te l'accorde, c'était un peu bas de ma part.
En revanche, le simple Stretch de Delphi n'utilise pas le système de moyenne de pixels, il prend simplement le pixel le plus proche. Donc si tu essayes de faire ça, dans les mêmes conditions, avec le Stretch de Delphi, tu verras que ça sera pas la même qualité (en tout cas dans Delphi 6 et 7, ça a peut-être changé dans les versions ultérieures).
C'est normal pour TrackbarChange, Downsample réduit l'image d'un facteur de deux, on l'appelle plusieurs fois pour obtenir une réduction plus importante. C'est voulu. Mais un point intéressant est que le coût de la fonction décroît exponentiellement à chaque appel, donc finalement appeller 4 fois Downsample ne serait que ~1.5 plus lent que de l'appeler une fois. Si ça avait été 4 fois plus lent j'aurai fait différemment.
Et oui je reconnais que ma clause try/except n'est pas terrible :( Mais bon, qui a des erreurs EOutOfMemory de nos jours :p
Merci pour tes remarques. Je vais particulièrement me pencher sur le problème du GetMem afin de corriger ça.
Serait-il plus intéressant de comparer ma fonction "simple" à une autre fonction identique, avec les mêmes conditions, mais utilisant Pixels par exemple ou Get/SetDIBits ? Ce serait alors honnête (je crois)
Cordialement, Bacterius !
PS : saurais-tu pourquoi appeller VirtualFree avec MEM_DECOMMIT ou MEM_RELEASE après un appel à VirtualAlloc avec MEM_COMMIT ne libère pas la mémoire correctement ? J'avais en tête d'utiliser ces fonctions pour obtenir une plage mémoire alignée pour que le CopyMemory aille plus vite, mais la mémoire ne se libérait pas proprement.
9 avril 2011 à 20:12
le code fonctionne sans modif sous delphi2010. Luc.
9 avril 2011 à 18:47
Ton bench n'est pas très honnête car tu compares ta fonction à des fonctions qui font bien plus de choses. C'est heureux que tu sois plus rapide dans ces conditions !
Si ta fonction devait aussi pouvoir
- agrandir
- traiter le pf24bit et autres formats
- accepter n'importe quelles largeurs de bitmap
- s'adapter à tous les facteurs d'agrandissement, même non entiers
- et j'en passe,
je te fiche mon billet que tu n'obtiendrais pas le même classement de performances.
Quand à la qualité, essaie d'utiliser le simple Stretch de Delphi dans les mêmes conditions, c'est à dire 1 bitmaps pf32bit de largeur et hauteur paires et avec un facteur de réduction de 4, 16, 64, etc... , je serais étonné que tu n'obtiennes pas exactement la même qualité.
TrackbarChange appelle 4 fois la fonction Downsample pour une réduction. Y'a quelque chose qui ne colle pas.
Ton GetMem(D, Q) est placé après le try. Si ton GetMem échoue, FreeMem est quand même appelé !
Sinon, c'est pas mal pour montrer l'utilisation des pointeurs.