Skip to content

Benchmark 1.0

Perchè questo plugin?
Secondo molti se io salvo un dato in un elemento DOM all’interno di una proprietà “expando” in fase di lettura sarò più veloce rispetto ad avere lo stesso dato in un attributo html.

Il plugin sembra confermare questa tesi.

Intanto cosa indica il grafico. Se spiego il grafico sarà più semplice capire come usare il plugin e testarlo per i vostri scopi.

Il grafico indica che all’aumentare degli elementi html su una pagina (in questo caso da uno a trenta immagini) effettivamente leggere un valore da un attributo html o leggere un valore dalla proprietà di un oggetto (lo stesso oggetto d’altra parte) sono due operazioni diverse e effettivamente una è più veloce dell’altra. E ci mancherebbe! La prima è un funzione di lettura/scrittura (oltretutto jQuery over DOM). La seconda è una lettura/scrittura nativa di una proprietà di un oggetto.

Le funzioni:


var mywrite = function(ref, serie){
    if(serie == 1)
        ref.original = jQuery(ref).attr("src");
    else
        jQuery(ref).attr("original", jQuery(ref).attr("src"));
}
var myread = function(ref, serie){
    if(serie  == 1){
        var read = ref.original;
        read = null;
    }else{
        var read = jQuery(ref).attr("original");
    }
}

il parametro serie indica quale test sto eseguendo. In questo caso io voglio un confronto tra “due alternative”. Avessi scritto delle funzioni più complesse potevo avere più test, e quindi più serie.
(Probabilmente cercando di influire il meno possibile sul test. La strada dell’if magari è da rivedere).

Test 0:
Scrittura:

jQuery(ref).attr(”original”, jQuery(ref).attr(”src”));

Lettura:

var read = jQuery(ref).attr(”original”);

Test 1:

Scrittura:

ref.original = jQuery(ref).attr(”src”);

Lettura:

var read = ref.original;

Ma come faccio a far eseguire queste funzioni?
Queste funzioni vengono passate al benchmark: vediamo come.

Innanzitutto questi benchmark sono “orientati al DOM” nel senso che io voglio testare la velocità di una certa azione su una pagina web.
Quindi mi serve una sorta di template html da creare per poi applicare la funzione.


var html = jQuery('<img alt="new Mikado logo 600 3D"  src="http://maxb.net/repository/images/14.jpg" />');

A questo punto setto il benchmark:


Benchmark.settings({
    maxc    : 30,
    args    : [0,1] ,
    mod     : 10,
    prepare : html
});

Questi settaggi mi dicono che

  • io ho due serie di test (args).
  • Che voglio testare su una pagina web formata da 30 elementi (maxc).
  • In realtà i test verranno eseguiti con un elemento in più alla volta fino ad arrivare ad avere 30 elementi. Il parametro mod mi permette di saltare ogni N elementi. In questo caso verranno eseguiti 3 test uno con 10, uno con 20, uno con 30 elementi (mod)
  • Che l’html da creare prima del test è contenuto nella variabile html (prepare)

Ecco il codice per il benchmark


Benchmark.each(function(nr, serie){
    jQuery(selector).benchmark({
        test    :   [ func1, func2 ] //….
    }, nr, serie);
});

La parte da personalizzare è l’array con i nomi di funzioni (o con funzioni anonime).

E il selettore.
Nel mio test ho dato da creare delle immagini. Il selettore sarà “img”.


Benchmark.each(function(nr, serie){
    jQuery('img').benchmark({
        test    :   [ mywrite , myread ]
    }, nr, serie);
});

Alla fine dei test verrà visualizzato tramite GOOGLE API CHARTS un grafico per capire al volo i risultati.

Vedere gli altri esempi :

Il test mi dice che il pack dei javascript non influisce sulla velocità.
Devo provare con le librerie jQuery UI.

Un confronto tra coda-slider 1.1.1 di Niall Doherty e il mio YCodaSlider.
Tutti questi dati non hanno alcuna valenza. Spero che mi permettano di capire dove è possibile migliorare le prestazioni e evitare memory leak. (Tra l’altro il mio plugin su poche istanze è più lento.)

  YCodaSlider 2.0 Coda-Slider 1.1.1
5 459ms 337ms
10 908ms 759ms
20 2069ms 2316ms
30 3497ms 4124ms
40 4327ms 6278ms
50 5386ms 9067ms

$Date: 2008-05-21 20:48:10 +0200 (mer, 21 mag 2008) $
$Rev: 106 $

corretto 2 bachi:
- il clone non può avere la stessa classe del target. Se si bisogna invocare il benchmark con un prefisso sul selettore target : Benchmark.prefix() + “.target”
- se il selettore seleziona più elementi di quanti il benchmark se ne aspettasse il benchmark non viene eseguito

TODO:
l’oggetto da clonare (options.prepare) deve poter essere un array in modo che ogni serie possa avere il suo clone da appendere.


/*
 *
 * Benchmark plugin 1.0
 * $Date: 2008-05-21 20:48:10 +0200 (mer, 21 mag 2008) $
 * $Rev: 106 $
 * @requires jQuery v1.2.3
 *
 * Copyright (c) 2008 Massimiliano Balestrieri
 * Examples and docs at: http://maxb.net/blog/
 * Licensed GPL licenses:
 * http://www.gnu.org/licenses/gpl.html
 *
 */

//http://www.dustindiaz.com/basement/sugar-arrays.html
Array.prototype.indexOf = function(el, start) {
    var start = start || 0;
    for ( var i=0; i < this.length; ++i ) {
        if ( this[i] === el ) {
            return i;
        }
    }
    return -1;
};

if(!window.Benchmark)
	Benchmark = {};

Benchmark = {
	show		:	false,
	start		:	false,
	finish		:	false,
	elapsed		:	false,
	flag		:	false,
	impossible	:	false,
	url			:	‘http://chart.apis.google.com/chart?’,
	maxv		:	0,
	maxc		:	0,
	data		:	[],
	labels		:	[],
	api			:	{},
	options 	: 	{},
	settings	:	function(options){
		Benchmark.options = jQuery.extend({
			maxc 	: 1	,//maxc : è il limite al ciclo
			args	: false	,//serie del grafico, ciclo esterno. passa parametro
			mod		: 1,	 //il benchmark salta ogni?
			prepare : false,
			clean   : true
		}, options);

		Benchmark.maxc = Benchmark.options.maxc;

		if(Benchmark.options.args === false)
			Benchmark.impossible = true;
	},
	chartapi	:	function(options){
		//http://chart.apis.google.com/chart
		Benchmark.api = jQuery.extend({
			dimensions 	: “1000×300″,
			chxt		: “x,y”,
			chds		: “0,”,
			chxr1		: “0,0,”,
			chxr2		: “1,0,”,
			cht			: “lc”,
			labels		: “”,
			chco		: “ff0000,00ff00″
		}, options);
		Benchmark.make_url();
	},
	chart	:	function(options){
		if(Benchmark.flag === false)
			Benchmark.chartapi(options);

		var dim = Benchmark.api.dimensions.split(”x”);
		jQuery(”body”).append(”<p>”+Benchmark.url+”</p>”);

		jQuery(”body”).append(’<img width=”‘+dim[0]+’” height=”‘+dim[1]+’” src=”‘+Benchmark.url+’” />’);
	},
	make_url:	function(){
		Benchmark.url	+=	‘chs=’ 	+ Benchmark.api.dimensions 	+ ‘&’;
		Benchmark.url	+=	‘chxt=’ + Benchmark.api.chxt 		+ ‘&’;
		Benchmark.url	+=	‘chds=’ + Benchmark.api.chds 		+ Benchmark.maxv	+	‘&’;
		Benchmark.url	+=	‘chxr=’	+ Benchmark.api.chxr1 		+ Benchmark.maxc	+	‘|’	+ Benchmark.api.chxr2 + Benchmark.maxv + ‘&’;
		Benchmark.url	+=	‘chl=0|’ 	+ Benchmark.labels.join(”|”)	+ ‘&’;

		var data = ”;
		for(serie in Benchmark.data)
			data += “0,” + Benchmark.data[serie].join(”,”) + “|”;
		data = data.substr(0, data.lastIndexOf(”|”));			

		Benchmark.url	+=	‘chd=t:’ 	+ data	+	‘&’;

		Benchmark.url	+=	‘cht=’ 	+ Benchmark.api.cht			+ ‘&’;
		Benchmark.url	+=	‘chdl=’ + Benchmark.api.labels.join(”|”) + ‘&’;
		Benchmark.url	+=	‘chco=’ + Benchmark.api.chco 		;
	},
	prepare :   function(p){
        jQuery(’<div id=”benchmark-dom’+p+’”>’).hide().appendTo(”body”);
        if(Benchmark.show)
        	jQuery(’#benchmark-dom’+p).show();
	},
	serie 	:	function(p, arg){
		jQuery(’#benchmark-dom’+p).append(’<div id=”serie-’+p + ‘-’ + arg +’ />’);
	},
	append  :	function(p, arg){
        for(var x = 1;x <= p; x++){
			var a = Benchmark.options.prepare.attr(”id”, “test-” + p + ‘-’ + arg + ‘-’ + x).clone();
    		jQuery(a).appendTo(’#serie-’+p+’-'+arg);
		}
	},
	clean	:	function(p, serie){
		jQuery(’#serie-’ + p + ‘-’+ serie).empty();
	},
	stop	:	function(benchmarkid, serie){

        Benchmark.finish = new Date().getTime();
		//console.log(”FINITO”);
		Benchmark.elapsed = Benchmark.finish - Benchmark.start;

		if(Benchmark.elapsed > Benchmark.maxv)
				    Benchmark.maxv = Benchmark.elapsed;

		//labels
		if(Benchmark.labels.indexOf(benchmarkid) == -1)
			Benchmark.labels.push(benchmarkid);

		//data
		if(!Benchmark.data[serie])
			Benchmark.data[serie] = [];

		Benchmark.data[serie].push(Benchmark.elapsed);

		Benchmark.start = Benchmark.elapsed = Benchmark.finish = false;

		if(Benchmark.options.clean)
			Benchmark.clean(benchmarkid, serie);

	},
	each	:	function(test){//test){

		if(Benchmark.impossibile)
			return;

		//console.log(”inizio i benchmark”);

		for(var p = 1;p <= Benchmark.maxc; p++){
			if(p % Benchmark.options.mod === 0){

				//console.log(”benchmark ” + p);

				if(Benchmark.options.prepare)
					Benchmark.prepare(p);

					//lavora sulle serie
					for(arg in Benchmark.options.args) {

						Benchmark.serie(p, arg);
						//console.log(”inizio la serie ” + arg + ” di ” + Benchmark.options.args[Benchmark.options.args.length -1]);

						Benchmark.append(p, arg);
						//console.log(”appendo i figli ” + p);

						//esegue init()
						test(p, arg);

					}
				}
		}

	},
	prefix : function(nr, serie){
        return ‘#benchmark-dom’ + nr +’ > #serie-’+ nr +’-'+ serie + ‘> ‘;
    },
	init	:	function(options, nr, serie){

		options = jQuery.extend({
			test 	: function(){}
		}, options);

		var container = jQuery(this);
		var size = container.size();

        if(nr != size)
		  alert(”Error. remove class from clone”);

        Benchmark.start = new Date().getTime();
		return jQuery(this, container).each(
			function(z){
				var that = this;
				for(func in options.test){
					options.test[func](that, serie);//eseguita la funzione utente
				} 

				if(z == (size -1))
					Benchmark.stop(nr, serie);//nr è più sicuro
			}
		);

	}
};	

jQuery.fn.benchmark = Benchmark.init;

Post a Comment

Your email is never published nor shared. Required fields are marked *