Autor Zpráva
1Pupik1989
Profil
Zdravím. Dneska nebudu tahat nic ošemetného.

Dlouhou dobu jsem brouzdal na jsperf a porovnával různé přístupy k proměnným polí a objektů. Bohužel nenašel jsem východisko jak udělat univerzální rychlé řešení pro všechny prohlížeče.

Testuji inverzní funkci pro matice zde. O matice vůbec nejde, jde o ukládání proměnných do pole "m" objektu. Jak můžete vidět, tak Firefox tam kulhá. Three.js to ukládá přímo jako proměnné svého objektu.

set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {

    this.n11 = n11; this.n12 = n12; this.n13 = n13; this.n14 = n14;
    this.n21 = n21; this.n22 = n22; this.n23 = n23; this.n24 = n24;
    this.n31 = n31; this.n32 = n32; this.n33 = n33; this.n34 = n34;
    this.n41 = n41; this.n42 = n42; this.n43 = n43; this.n44 = n44;

    return this;

}

Kdežto já jako pole.

this.m = [
      n0*det,
      -(m1*(m10*m15-m11*m14) - m2*(m9*m15-m11*m13) + m3*(m9*m14-m10*m13))*det,
      (m1*(m6*m15-m7*m14) - m2*(m5*m15-m7*m13) + m3*(m5*m14-m6*m13))*det,
      -(m1*(m6*m11-m7*m10) - m2*(m5*m11-m7*m9) + m3*(m5*m10-m6*m9))*det,
      -n4*det,
      (m0*(m10*m15-m11*m14) - m2*(m8*m15-m11*m12) + m3*(m8*m14-m10*m12))*det,
      -(m0*(m6*m15-m7*m14) - m2*(m4*m15-m7*m12) + m3*(m4*m14-m6*m12))*det,
      (m0*(m6*m11-m7*m10) - m2*(m4*m11-m7*m8) + m3*(m4*m10-m6*m8))*det,
      n8*det,
      -(m0*(m9*m15-m11*m13) - m1*(m8*m15-m11*m12) + m3*(m8*m13-m9*m12))*det,
     (m0*(m5*m15-m7*m13) - m1*(m4*m15-m7*m12) + m3*(m4*m13-m5*m12))*det,
     -(m0*(m5*m11-m7*m9) - m1*(m4*m11-m7*m8) + m3*(m4*m9-m5*m8))*det,
     -n12*det,
     (m0*(m9*m14-m10*m13) - m1*(m8*m14-m10*m12) + m2*(m8*m13-m9*m12))*det,
     -(m0*(m5*m14-m6*m13) - m1*(m4*m14-m6*m12) + m2*(m4*m13-m5*m12))*det,
     (m0*(m5*m10-m6*m9) - m1*(m4*m10-m6*m8) + m2*(m4*m9-m5*m8))*det
];

Další zvláštnost co nechápu, je fakt, že když použiji svoji funkci this.set();, tak se počet operací sníží na čtvrtinu.

Viz.:
set:function(n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15){
    this.m = [n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15];
  }

Napadá mě jediná možnost a to zjistit rychlost při načtení souboru. Nebo druhá varianta podle prohlížeče nastavit, jestli bude proměnná pole nebo objekt. Nicméně fajn by bylo, kdyby se našlo jednodušší a efektivnější řešení.

Za každou radu děkuji.
_es
Profil
1Pupik1989:
A problém je v čom? V tom, že ťa prekvapuje, že nejaký skript dokáže v nejakom prehliadači pracovať efektívnejšie než iný skript?
1Pupik1989
Profil
Nejde o to, že jeden skript je rychlejší než druhý. Jde o to, že do proměnné objektu (three.js) to zapíše rychleji než do pole. Přitom dám další test pro porovnání čtení/zápis pole/objekt a pro operu vyjde pole. Takže hledám chybu, proč je ten můj skript pomalejší než by měl.


//edit: Omyl, není to v Opeře, ale ve Firefoxu.
1Pupik1989
Profil
Nezná někdo nějaké jiné fórum o webdesignu či lépe o javascriptu? Tentokrát už si asi neporadím sám.

Slibuji, že už jsem nenapíšu.
1Pupik1989
Profil
Nakonec vyřešeno dvěma objekty.
_es
Profil
1Pupik1989:
Slibuji, že už jsem nenapíšu.
Problém bol v tom, že akosi nebolo jasné, akú konkrétnu radu chceš. To si čakal, že bude niekto analyzovať tvoje skripty, rôzne ich prerábať a modifikovať a vykonávať na rôznych prehliadačoch s nimi výkonové testy?
1Pupik1989
Profil
Aha, zkusím to nějak rozepsat.

Mám konstruktor třeba "Matrix".

function Matrix(){};

Teď v něm potřebuji uložit 16 hodnot. No a tady začíná ten problém.

Pokud v konstruktoru vytvořím pole "m", pak přístupová rychlost v Chrome je super, jenže ostatním prohlížečům se to moc nelíbí.
function Matrix(n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15){
      this.m = ([n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15]);
      
      return this;
    };


Tak jsem zkusil tedy druhou nejrychlejší možnost. Uložit prostě proměnné přímo v konstruktoru.
function Matrix(n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15){
      this.m0 = n0; this.m1 = n1; this.m2 = n2; this.m3 = n3;
      this.m4 = n4; this.m5 = n5; this.m6 = n6; this.m7 = n7;
      this.m8 = n8; this.m9 = n9; this.m10 = n10; this.m11 = n11;
      this.m12 = n12; this.m13 = n13; this.m14 = n14; this.m15 = n15;
      
      return this;
    };

To se líbí všem, ovšem zase chrome tam je jako zaseknutý. Pokud do konstruktoru přidám podmínku.
function Matrix(n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15){
  if(chrome){
    this.m = ([n0,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11,n12,n13,n14,n15]);
  }else{
    this.m0 = n0; this.m1 = n1; this.m2 = n2; this.m3 = n3;
    this.m4 = n4; this.m5 = n5; this.m6 = n6; this.m7 = n7;
    this.m8 = n8; this.m9 = n9; this.m10 = n10; this.m11 = n11;
    this.m12 = n12; this.m13 = n13; this.m14 = n14; this.m15 = n15;
  }
  return this;
};

Tak jediné co tím vyřeším, je propad rychlosti asi tak 10x.
No a moje otázka zní: "Jak by mohlo nebo jaké by bylo univerzální řešení pro všechny prohlížeče?" Nenapadlo mě nic jiného, než vytvořit dva objekty a nastavit přímo ten konkrétní pro prohlížeč. Jenže to je zase spoustu zbytečného kódu navíc.
_es
Profil
1Pupik1989:
Pri nejakom zložitom výpočte v JS a prístupu k veľa rôznym hodnotám by z hľadiska len efektivity rýchleho prístupu k tým hodnotám malo pomôcť všetky tie hodnoty uložiť do lokálnych premenných funkcie. Asi by bolo dobré aj trochu osvetliť, čo vlastne ten test vo výsledku testuje.
1Pupik1989
Profil
Ten test ve výsledku vlastně testuje pouze rychlost přístupu k těm proměnným. Nejlépe jak otestovat tu rychlost, mě právě napadlo vypočítat inverzní matici 4x4. Opět jsem jí předělal, teď funguje Revize 7..

To s těmi lokálními je dobrý nápad. Vůbec mě to nenapadlo.
function Matrix(m0,m1,m2,m3,m4,m5,m6,m7,m8,m9,m10,m11,m12,m13,m14,m15){
  return {
    inverse:function(){
      var n0 = m5*(m10*m15-m11*m14 - m6*(m9*m15-m11*m13) + m7*(m9*m14-m10*m13)),
        n4 = m4*(m10*m15-m11*m14) - m6*(m8*m15-m11*m12) + m7*(m8*m14-m10*m12),
        n8 = m4*(m9*m15-m11*m13) - m5*(m8*m15-m11*m12) + m7*(m8*m13-m9*m12),
        n12 = m4*(m9*m14-m10*m13) - m5*(m8*m14-m10*m12) + m6*(m8*m13-m9*m12),
        det = 1/(m0*n0 + m1*n4 - m2*n8 + m3*n12);
    
      m0 = n0*det;
      m1 =  -(m1*(m10*m15-m11*m14) - m2*(m9*m15-m11*m13) + m3*(m9*m14-m10*m13))*det;
      m2 = (m1*(m6*m15-m7*m14) - m2*(m5*m15-m7*m13) + m3*(m5*m14-m6*m13))*det;
      m3 = -(m1*(m6*m11-m7*m10) - m2*(m5*m11-m7*m9) + m3*(m5*m10-m6*m9))*det;
      m4 = -n4*det;
      m5 = (m0*(m10*m15-m11*m14) - m2*(m8*m15-m11*m12) + m3*(m8*m14-m10*m12))*det;
      m6 = -(m0*(m6*m15-m7*m14) - m2*(m4*m15-m7*m12) + m3*(m4*m14-m6*m12))*det;
      m7 = (m0*(m6*m11-m7*m10) - m2*(m4*m11-m7*m8) + m3*(m4*m10-m6*m8))*det;
      m8 = n8*det;
      m9 = -(m0*(m9*m15-m11*m13) - m1*(m8*m15-m11*m12) + m3*(m8*m13-m9*m12))*det;
      m10 = (m0*(m5*m15-m7*m13) - m1*(m4*m15-m7*m12) + m3*(m4*m13-m5*m12))*det;
      m11 = -(m0*(m5*m11-m7*m9) - m1*(m4*m11-m7*m8) + m3*(m4*m9-m5*m8))*det;
      m12 = -n12*det;
      m13 = (m0*(m9*m14-m10*m13) - m1*(m8*m14-m10*m12) + m2*(m8*m13-m9*m12))*det;
      m14 = -(m0*(m5*m14-m6*m13) - m1*(m4*m14-m6*m12) + m2*(m4*m13-m5*m12))*det;
      m15 = (m0*(m5*m10-m6*m9) - m1*(m4*m10-m6*m8) + m2*(m4*m9-m5*m8))*det;

      return this;
    } 
  };            
};

Takže zhruba takto by to mohlo vypadat? Navíc nebudu muset používat operátor new.


//edit: Tak odvolávám, ten kód je blbost.
_es
Profil
1Pupik1989:
Ten test ve výsledku vlastně testuje pouze rychlost přístupu k těm proměnným.
Netestuje rýchlosť výpočtu inverznej matice? (Tip podľa názvu metód)
1Pupik1989
Profil
To jo, je to výpočet na inverzní matici. Stejně tak to ale může násobení, sčítání, odčítání, dělení atd.

Mě jde hlavně o část:

var m0 = this.m[0], m1 = this.m[1], m2 = this.m[2], m3 = this.m[3],
        m4 = this.m[4], m5 = this.m[5], m6 = this.m[6], m7 = this.m[7],
        m8 = this.m[8], m9 = this.m[9], m10 = this.m[10], m11 = this.m[11],
        m12 = this.m[12], m13 = this.m[13], m14 = this.m[14], m15 = this.m[15],

a o:
this.m = ([
      n0*det,
      -(m1*(m10*m15-m11*m14) - m2*(m9*m15-m11*m13) + m3*(m9*m14-m10*m13))*det,
      (m1*(m6*m15-m7*m14) - m2*(m5*m15-m7*m13) + m3*(m5*m14-m6*m13))*det,
      -(m1*(m6*m11-m7*m10) - m2*(m5*m11-m7*m9) + m3*(m5*m10-m6*m9))*det,
      -n4*det,
      (m0*(m10*m15-m11*m14) - m2*(m8*m15-m11*m12) + m3*(m8*m14-m10*m12))*det,
      -(m0*(m6*m15-m7*m14) - m2*(m4*m15-m7*m12) + m3*(m4*m14-m6*m12))*det,
      (m0*(m6*m11-m7*m10) - m2*(m4*m11-m7*m8) + m3*(m4*m10-m6*m8))*det,
      n8*det,
      -(m0*(m9*m15-m11*m13) - m1*(m8*m15-m11*m12) + m3*(m8*m13-m9*m12))*det,
     (m0*(m5*m15-m7*m13) - m1*(m4*m15-m7*m12) + m3*(m4*m13-m5*m12))*det,
     -(m0*(m5*m11-m7*m9) - m1*(m4*m11-m7*m8) + m3*(m4*m9-m5*m8))*det,
     -n12*det,
     (m0*(m9*m14-m10*m13) - m1*(m8*m14-m10*m12) + m2*(m8*m13-m9*m12))*det,
     -(m0*(m5*m14-m6*m13) - m1*(m4*m14-m6*m12) + m2*(m4*m13-m5*m12))*det,
     (m0*(m5*m10-m6*m9) - m1*(m4*m10-m6*m8) + m2*(m4*m9-m5*m8))*det
    ]);

Abych tu rychlost přístupu k oné proměnné var m0 = this.m[0]; nebo var m0 = this.m0; sjednotil a běželo to ve všech prohlížečích co nejrychleji. Nejde o to, že někoho mám nutnost porazit. Dělám to pro svojí online hru, kterou jsem se rozhodl udělat komplet od začátku, čili bez použití nějaké knihovny typu three.js, gl, closure atd.
_es
Profil
1Pupik1989:
To jo, je to výpočet na inverzní matici.
To ale potom si musíš zanalyzovať, koľko je na ten výpočet potrebných operácií a s akou náročnosťou. Násobenie je náročnejšie ako súčet a pod. Spôsob uloženia medzivýsledkov môže byť zanedbateľný a môže len nepriamo ovplyvňovať náročnosť výpočtu.

rychlost přístupu k oné proměnné var m0 = this.m[0]; nebo var m0 = this.m0;
Druhý prístup mal byť rýchlejší. Je v ňom o jeden prístup k vlastnosti objektu menej. Ak vo výsledku nie je, tak je problém asi inde.

Pri nejakej optimalizácii na prístup k uloženým hodnotám, ak je x lokálna premenná, by mal byť prístup k x rýchlejší ako k objekt.vlastnosť. No rôzne prehliadače používajú rôzne vnútorné optimalizácie.
1Pupik1989
Profil
Ano, přístup var m0 = this.m0; by měl být rychlejší, nicméně přístup k proměnné a potom k poli var m0 = this.m[0]; to v chrome předčí.

Dá se to krásně demonstrovat na příkladu.
_es
Profil
1Pupik1989:
Lenže ty testuješ časť tej JS knižnice a nemôžeš vedieť, aké vedľajšie efekty tým nastanú. Ak chceš testovať prístup k premennej a prístup k poľu, musí spraviť testy, kde sa bude testovať len prístup k premennej a len prístup k poľu, nie nejaké zložité funkcie, u ktorých nie je zrejmé, ako sa s nimi prehliadač vysporiada.
1Pupik1989
Profil
Dobrá tedy. Čistě jen test Čtení/Zápis Objeckt/Pole . Výsledek je ale stejný.

Napadlo mě pole deklarovat ještě předtím, než ho pošlu do funkce. Tudíž bych nemusel používat žádný konstruktor.
_es
Profil
1Pupik1989:
Nemôžeš vedieť, aké rôzne optimalizácie rôzne prehliadače robia - musíš to testovať v nejakých reálnejších situáciách. Výpočet, ktorý je „zahodený“, a je len výpočtom, môže byť napríklad ignorovaný a pod. Či nie je problém skôr s uvoľňovaním použitej pamäti, testovať by sa malo na náhodné vstupné hodnoty a pod.

Môžeš ešte vyskúšať objekt vytvárať cez literálový výraz:
objekt={vlastnosť1:výraz1, vlastnosť2:výraz2,...};
namiesto objekt.vlastnosť1=výraz;objekt.vlastnosť2=výraz2;...
či vytvárania poľa.
1Pupik1989
Profil
Literální zápisy jsou poslední dvě položky v testu. Na náhodné hodnoty to je opět stejné, vždycky to je stejné. Tohle je vlastně všechno taková omáčka, Já potřebuji jen vymyslet takový konstruktor objektu, který v chrome vytvoří pole a v ostatních to zapíše přímo do objektu. Minimálně 20 stylů zápisů jsem otestoval a vím, že ty dva co tu omílám jsou nejrychlejší. Pokud do konstruktoru přidám podmínku, tak si můžu jít rovnou hodit mašli, protože rychlost ve všech prohlížečích klesne tak na úroveň IE.
_es
Profil
1Pupik1989:
Pokud do konstruktoru přidám podmínku.
Môžeš podľa tej podmienky vytvárať odlišný konštruktor či odlišné metódy - ešte pred použitím tvojej JS knižnice.

Pokiaľ ti ide o nejakú extrémnu optimalizáciu na rýchlosť, tak spomaľovať môžu aj všelijaké, nie nutné, „objektové obaly“, trebárs prechádzanie k prototypu objektu, nejaká „dedičnosť“ a pod. Alebo, prečo nepracuješ s tou maticou rovno ako s poľom, ale robíš okolo toho poľa nejaký objektový obal a pristupuješ k nemu ako k vlastnosti objektu?
1Pupik1989
Profil
_es:
robíš okolo toho poľa nejaký objektový obal a pristupuješ k nemu ako k vlastnosti objektu

Chtěl jsem rozlišit hlavně funkce, které vytvoří novou matici a funkce, které pracují s tou onou, kterou potřebuji. Asi to ale dopadne jak píšeš. Prostě udělám funkci Matrix.Inverse, kde první vstupní parametr bude pole.

Třeba:
matice.inverse(); Měla změnit přímo pole té matice a Matrix.Inverse(matice) měla v z objektu matice vypočítat inverzi a vytvořit novou matici.

Když jako parameter budu ale posílat literální pole, tak to opět klesne u ostatních prohlížečů. Teď jsem to zatím udělal podmínkou.
var Matrix4 = (window.chrome) ? Matrix4a : Matrix4o;
Kde Matrix4a ukládá jako svoji vlastnost pole a Matrix4o ukládá všech 16 hodnot do sebe jako vlastnost. Pravda není to elegatní těmi tuny kódu navíc, ale zatím to funguje. Zbytek funkcí jako třeba Matrix4.CreateRotationX už jsou sdílené a pro obojí stejné. viz níže:

Matrix4.CreateRotationX = function(angle){
  var c = Math.cos(angle);
  var s = Math.sin(angle);

  return new this(
    1,0,0,0,
    0,c,-s,0,
    0,s,c,0,
    0,0,0,1
  );
};

Ta už vytvoří objekt podle nastaveného konstruktoru.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: