Pb memory
Philippe29-May-2018/8:27:37
Bonjour à tous,

Je me suis éloigné du Rebol depuis quelques années, mais je regarde encore de temps en temps ce qu'il se passe sur le forum et bien sûr sur Red.
Pour les besoins d'un projet, j'ai déterré un bout de code que j'avais fait il y a fort fort longtemps et qui permet d'extraire d'un log (ici Apache) les temps de requêtes et de créer un graphe par minute du nombre de hits et en fonction du temps de la requête le hit est sous forme d'une box plus ou moins colorée.
Je me heurte à un souci de mémoire de Rebol dès que je veux agrandir la taille de la box ou d'un nombre important de hits .
Si quelqu'un a une idée d'optimisation, je suis preneur, car je suis un peu (beaucoup) rouillé !!

Les données (anonymisées) se présentent comme cela (l'avant-avant-dernier chiffre est le temps de la requête en microsecondes ) :

[24/05/2018:00:43:01]|TEST|TEST|TEST|TEST|TEST|TEST|245880|0|200
[24/05/2018:00:43:00]|TEST|TEST|TEST|TEST|TEST|TEST|1463436|0|200
[24/05/2018:00:43:01]|TEST|TEST|TEST|TEST|TEST|TEST|2208594|2|200
[24/05/2018:00:43:02]|TEST|TEST|TEST|TEST|TEST|TEST|1572024|0|200


et le code :

rebol []

change-dir %/tmp/stats

; limits = [L1 L2 L3 L4] bornes qualité temps de réponse 1s 2s 5s 10s
limits: [1000000 2000000 5000000 10000000] 
sizeu:  1x10
pixel-size: 35x10     ; taille d'un rectangle de couleur
pixel-dir: 1x0        ; pour mettre les rectangles cote à cote

get-tuple!: func [val limX limY /local var ][to-integer ((255 * ((to-integer val) - limX)) / (limY - limX))] ; end func
time-to-color!: func [ value /local var ][
	value: to-integer value
	if (lesser-or-equal? value limits/1) [var: 0.255.0]  ; < L1 green, all seems good
	if all [(greater? value limits/1) (lesser-or-equal? value limits/2)] [ var:  to-tuple reduce [(get-tuple! value limits/1 limits/2) 255 0] ]
	; beetween L1, and L2, 0.255.0 -> 255.255.0 vert au jaune
	if all [(greater? value limits/2) (lesser-or-equal? value limits/3)] [ var: to-tuple reduce [255 (get-tuple! value limits/3 limits/2) 0] ]
	; beetween L2, and L3, 255.255.0 -> 255.0.0 jaune au rouge
	if all [(greater? value limits/3) (lesser-or-equal? value limits/4)] [ var: to-tuple reduce [(get-tuple! value limits/4 limits/3) 0  0] ]
	; beetween L3, and L4, 255.0.0 -> 0.0.0 rouge au noir
	if (greater? value limits/4) [ var: 0.0.0 ]  ; > L4, black, careful
	return var
] ; end func

; ------ MAIN / INIT  ---------------------------
; on crée un tableau de minutes [ 00:00 00:01 00:02 ... 23:59 ]
tableau-minutes: copy []
for v 00:00 23:59 00:01 [
	append tableau-minutes  either (lesser? v 10:00) [rejoin ["0" v] ][form v]
	append/only tableau-minutes copy []
	]
;==tableau-minutes: ["00:00" [] "00:01" [] "00:02" [] ... "23:59" [] ]

; -----reading input files ----
datas: read/lines request-file/only
; ------ MAIN / PARSING ZONE  ---------------------------

foreach line datas [
	tabinfos: parse line {[]"| }					; tabinfos/4 = date  |  tabinfos/12 = temps_requete
	timer: (val: parse tabinfos/2 {:}  rejoin [val/2 ":" val/3])	; timer= heure dans la ligne de log
;	probe tabinfos/12
	if find tableau-minutes :timer [repend tableau-minutes/:timer (time-to-color! tabinfos/12 )]   ;  tabinfos/9)]
] ; end foreach

tableau-data: copy tableau-minutes

; -------- MAIN / Building Image ----------------------------
out: [
	origin 0
	backeffect [gradient 0x1 white white]  ; silver
	across
	space 1x1
]

; --- basic face for reduce memory -----------
simple-image: make object! [
	type: 'face      ; mandatory
	offset: 0x0   ; mandatory
	size: pixel-size   ; mandatory
	span: none    ; mandatory
	pane: none  ; mandatory
	text: "basic image"  ; mandatory  (sinon erreur titre)
	color: 255.255.255   ;(black by default if no color attribute)
	feel: make object! [ ]   ; erreur si feel absent
]
; ------ prepapre statement ---
foreach [label-hour tab-colors]  tableau-data [
	;blk-img: clear []
		img: make image! pixel-size * as-pair length? tab-colors 1
		; position où on dessine dans l'image
		pos: 0x0
	if (not empty? tab-colors) [
		; pour chaque couleur
		foreach colr tab-colors [
			; append blk-img compose/deep [image (make image! compose/deep [(sizeu) (colr) ])]
			img: draw img compose [pen (colr) fill-pen (colr) box (pos) (pos + pixel-size)]
			; position du rectangle suivant
			pos: pos + pixel-size * pixel-dir
		] ; end foreach
	]
	append out compose/deep [
		;text (label-hour)
		;pad 10x0
		;(blk-img)
		text (to-string label-hour) 40
		image (img)
		return
	]
]
;write clipboard:// mold out
code: compose/deep [layout [(out)]  ]
code: do code
;view/new center-face code
;unview/only code

; ---- PB de memoire ---------
recycle

res-img: to-image code
composite-file: %/tmp/stats/test-analyse-apacheX.png
save/png composite-file res-img

print rejoin [ "End ... : "]
halt


Merci de votre aide

===Philippe
Darkblue30-May-2018/14:13:42
Bonjour Philippe,
tu pourrais dans un 1er temps ne pas faire
tableau-data: copy tableau-minutes
mais utiliser tableau-minutes simplement
Tu peux aussi ne pas faire de read/lines du fichier s'il est volumineux m'ai d'ouvrir un port en lecture ligne par ligne avec open/read/lines/direct

Olivier
DideC2-Jul-2018/7:22:42
Il y a surement pas mal d'autres optimisations.
Mais je pense que ça :
code: compose/deep [layout [(out)]  ]
code: do code

...est tout simplement équivalent à :
[ocde]code: layout out[/code]
DideC2-Jul-2018/7:41:31
Tu peux aussi pas mal optimiser le code du départ et attention au nommage des fonctions (to-tuple! ne renvoyant pas un tuple! ??!!)
get-color-amount: func [val limX limY /local var ][to integer! (to integer! val) - limX * 255 / (limY - limX)]

time-to-color: func [value /local var] [
	value: to integer! value
	return case [
  		; < L1 green, all seems good
  		value <= limits/1 [0.255.0]
		; beetween L1, and L2, 0.255.0 -> 255.255.0 vert au jaune
		value <= limits/2 [to tuple! reduce [get-color-amount value limits/1 limits/2  255 0]]
		; beetween L2, and L3, 255.255.0 -> 255.0.0 jaune au rouge
		value <= limits/3 [to tuple! reduce [255  get-color-amount value limits/3 limits/2  0]]
		; beetween L3, and L4, 255.0.0 -> 0.0.0 rouge au noir
		value <= limits/4 [to tuple! reduce [get-color-amount value limits/4 limits/3  0 0]]
		; > L4, black, careful
		true [0.0.0]
	]
]
DideC2-Jul-2018/8:24:32
Et puis dans ton tableau-minute, tu peux surtout stocker tes étiquettes sous forme de time! plutôt que de string!, cela prendra moins de mémoire et accélérera les recherches. Tu fais déjà la conversion en string pour l'affichage.
De manière générale, il y a bien trop de 'reduce et 'compose inutiles qui te consomme pas mal de mémoire.

Voilà ma version plus épurée mais gardant la même logique :
Rebol []

limits: [1000000 2000000 5000000 10000000]
sizeu:  1x10
pixel-size: 35x10     ; taille d'un rectangle de couleur
pixel-dir: 1x0        ; pour mettre les rectangles cote à cote

get-color-amount: func [val limX limY /local var ][to integer! (to integer! val) - limX * 255 / (limY - limX)]

time-to-color: func [value /local var] [
	value: to integer! value
	return case [
  		; < L1 green, all seems good
  		value <= limits/1 [0.255.0]
		; beetween L1, and L2, 0.255.0 -> 255.255.0 vert au jaune
		value <= limits/2 [to tuple! reduce [get-color-amount value limits/1 limits/2  255 0]]
		; beetween L2, and L3, 255.255.0 -> 255.0.0 jaune au rouge
		value <= limits/3 [to tuple! reduce [255  get-color-amount value limits/3 limits/2  0]]
		; beetween L3, and L4, 255.0.0 -> 0.0.0 rouge au noir
		value <= limits/4 [to tuple! reduce [get-color-amount value limits/4 limits/3  0 0]]
		; > L4, black, careful
		true [0.0.0]
	]
]

tableau-minutes: []    ; 'copy inutile ici
for v 00:00 23:59 00:01 [
	append tableau-minutes reduce [v copy []]
]

; -----reading input files ----
;datas: read/lines request-file/only

; pour les test de ceux qui n'ont pas ton logs ;-)
datas: [
{[24/05/2018:00:40:01]|TEST|TEST|TEST|TEST|TEST|TEST|245880|0|200}
{[24/05/2018:00:40:00]|TEST|TEST|TEST|TEST|TEST|TEST|1463436|0|200}
{[24/05/2018:00:43:01]|TEST|TEST|TEST|TEST|TEST|TEST|2208594|2|200}
{[24/05/2018:00:43:02]|TEST|TEST|TEST|TEST|TEST|TEST|1572024|0|200}
{[24/05/2018:01:43:01]|TEST|TEST|TEST|TEST|TEST|TEST|245880|0|200}
{[24/05/2018:03:23:00]|TEST|TEST|TEST|TEST|TEST|TEST|1463436|0|200}
{[24/05/2018:04:13:01]|TEST|TEST|TEST|TEST|TEST|TEST|2208594|2|200}
{[24/05/2018:04:14:02]|TEST|TEST|TEST|TEST|TEST|TEST|1572024|0|200}
]

; ------ MAIN / PARSING ZONE  ---------------------------
foreach line datas [
	tabinfos: parse line {[]"| }					; tabinfos/4 = date  |  tabinfos/12 = temps_requete
	timer: to time! find/tail tabinfos/2 {:}		; on ne garde que ce qui est après le 1er ":" = l'heure
	timer/second: 0									; on ne veut que heure:minute:0
	append select tableau-minutes timer time-to-color tabinfos/12   ;  tu as souvent des 'reduce ou 'compose inutiles = prend de la mémoire pour rien
]

; -------- MAIN / Building Image ----------------------------
out: [
	origin 0
	backeffect [gradient 0x1 white white]  ; silver
	across
	space 1x1
]

; --- basic face for reduce memory -----------

comment {		; PAS UTILISE ?!
simple-image: make object! [
	type: 'face      ; mandatory
	offset: 0x0   ; mandatory
	size: pixel-size   ; mandatory
	color: 255.255.255	;(black by default if no color attribute)
	span: pane: feel: text: none  ; mandatory
]
}

; ------ prepapre statement ---
foreach [label-hour tab-colors] tableau-minutes [
	img: make image! pixel-size * as-pair length? tab-colors 1
	pos: 0x0
	foreach colr tab-colors [
		img: draw img compose [pen (colr) fill-pen (colr) box (pos) (pos + pixel-size)]
		pos: pos + pixel-size * pixel-dir
	] ; end foreach
	append out compose/deep [
		text (to-string label-hour) 40 (either label-hour/minute = 0 ['bold]['black])  ; J'AI AJOUTE CA pour avoir un repère visuel sur les heures
		image (img)
		return
	]
]
code: layout out

; ---- PB de memoire ---------
;recycle
composite-file: %/C/Users/Didier.2CBI/Desktop/test-analyse-apacheX.png
save/png composite-file to image! code

print rejoin [ "End ... : "]
halt

Login required to Post.


Powered by RebelBB and REBOL 2.7.8.4.2