Olen heittänyt jakoon koneeltani kaiken näköistä satunnaista koodia, joka voi olla hyödyksi. Varoituksena sanottakoon, että osa jaossa näkyvästä koodista on keskeneräistä, mm. IRC-hakemiston sisältö on toistaiseksi pääosin hyödytöntä (kirjoitan uutta versiota UniSock-luokasta, nykyisellään se pahalainen ei vaan suostu toimimaan vakaasti kun se on orjuutettu toisen luokan sisään).
Classes ja Modules -hakemistoista löytyy loppuun asti ajateltua koodia. Sinne ilmestynee ajan myötä aina lisää tavaraa kun löydän laajasta koodikirjastostani jotakin hyödyllistä ja toimivaa jaettavaksi asti.
Zip-hakemistossa on päivittäiset varmuuskopiot, jotka otetaan tunnin välein.
Osoite on http://kontu.selfip.info/vb6/projects/ - ja hakemisto on sitten estetty hakuroboteilta, että ihan vain ihmissilmille tarkoitettua ruokaa kyseessä.
Muistutuksena VB6:n hyödyllisyydestä: VB6:lla tehtyjen ohjelmien tuki jatkuu Vistan elinkaaren loppuun asti, eli msvbvm60.dll pidetään toimintakunnossa Vistassa ja Windows Server 2008:ssa kyseisten tuotteiden tuen loppuun (semmoiset kahdeksan vuotta vielä). Vistassa kait lähes ainut VB6:n rikkoutunut ominaisuus on SendKeys. VB6:n tila seuraavan Windowsin osalta on tuntematon. Yleisesti veikataan että tuki heivataan, mutta toisaalta mielipiteitä on toiseenkin suuntaan.
Sinänsä mukavaa, että on valmis jakamaan tuotoksiaan muiden kanssa, mutta valitettavasti äkkiseltään kun katsoin niin valtaosa oli kielessä jo olevien toiminnallisuuksien uudelleentoteutusta. Tai sitten vaan ne muutamat moduulit joita katsoin sattuivat olemaan huonoja esimerkkejä.
Aika paljon olet kyllä jaksanut tehdä ylimääräistä työtä, kun miettii esim.
Public Function ColorToHex(ByVal Color As Long) As String ' 12 bytes = 6 characters = 0 To 11 Dim bytOut(11) As Byte ' make a character: take 4 bits, move them to be the lowest 4 bits, ' combine bitwise with character code 48, you will get a value from range 48 to 63 (&H30 to &H3F) bytOut(0) = &H30& Or ((Color And &HF0&) \ &H10&) ' take 4 bits and combine bitwise with 48 bytOut(2) = &H30& Or (Color And &HF&) ' take 4 bits and move them to be the lowest 4 bits bytOut(4) = &H30& Or ((Color And &HF000&) \ &H1000&) ' I guess you got it by now bytOut(6) = &H30& Or ((Color And &HF00&) \ &H100&) bytOut(8) = &H30& Or ((Color And &HF00000) \ &H100000) bytOut(10) = &H30& Or ((Color And &HF0000) \ &H10000) ' because the resulting characters are until now from range ' ' 0123456789:;<=>? ' ' and we want them to be from range ' ' 0123456789 ABCDEF ' ....... <- 7 characters we do not want ' ' we increase character codes above 57 by 7 - this gives us a range from 48 - 57 and 65 to 70 If bytOut(0) > &H39 Then bytOut(0) = bytOut(0) + 7 If bytOut(2) > &H39 Then bytOut(2) = bytOut(2) + 7 If bytOut(4) > &H39 Then bytOut(4) = bytOut(4) + 7 If bytOut(6) > &H39 Then bytOut(6) = bytOut(6) + 7 If bytOut(8) > &H39 Then bytOut(8) = bytOut(8) + 7 If bytOut(10) > &H39 Then bytOut(10) = bytOut(10) + 7 ' finally, make a real string out of the byte array ColorToHex = bytOut End Function
vs.
Public Function ColorToHex(ByVal Color As Long) As String ColorToHex = Right("00000" & Hex(Color), 6) ColorToHex = Right(ColorToHex, 2) & Mid(ColorToHex, 3, 2) & Left(ColorToHex, 2) End Function
tai
Public Function ColorToHex(ByVal Color As Long) As String ColorToHex = Right("00000" & Hex( _ Color \ &H10000 + _ ((Color \ 256) And 255) * 256 + _ (Color And 255) * &H10000), 6) End Function
Funktiot ovat hitausjärjestyksessä, joten silläkään ei tuota ekaa versiota voi perustella.
Koodeissa on siis seassa myös toisenlaisten tekniikoiden näytteitä, mihin tuo ColorToHex myöskin kuuluu. Monilta tuntuu mm. menevän täysin yli ymmärryksen, mitä Hex$ oikeastaan tekeekään. Hitausjärjestysväitteesi ei pidä ihan paikkaansa, varsinkin koodin kääntämisen jälkeen tuo ensimmäinen on lähes yhtä nopea kuin viimeinenkin esimerkkisi, keskimmäisen ollessa se hidas tapaus.
Viimeisen suorituskykyä voi sitäkin parantaa huomattavasti parilla pienellä muutoksella:
Public Function ColorToHex3(ByVal Color As Long) As String ColorToHex3 = RightB$("00000" & Hex$( _ ((Color And &HFF0000) \ &H10000) Or _ ((Color And &HFF00&) \ &H100&) * &H100& Or _ (Color And &HFF&) * &H10000), 12) End Function
Pitämällä muuttujatyypin laskujen puolella 32-bittisenä, käyttämällä Oria ja ennen kaikkea pitäen merkkijonot merkkijonoina eikä loiki varianttien kautta saa nopeutta sellaisen kolmanneksen lisää. Korjasin myös yhden laskuvirheen mahdollisuuden.
Tämä on kuitenkin vielä yli puolet nopeampi:
Public Function ColorToHex2(ByVal Color As Long) As String Static lngInit As Long, strHex As String * 6, strHexes(255) As String If Not lngInit Then For lngInit = 255 To 0 Step -1 strHexes(lngInit) = RightB$("0" & Hex$(lngInit), 4) Next lngInit End If MidB$(strHex, 1, 4) = strHexes((Color And &HFF0000) \ &H10000) MidB$(strHex, 5, 4) = strHexes((Color And &HFF00&) \ &H100&) MidB$(strHex, 9, 4) = strHexes(Color And &HFF&) ColorToHex2 = strHex End Function
Ensimmäinen kutsu on hidas, mutta sen jälkeen tahti on huomattavasti virkeämpää. Vauhtihan johtuu siitä, että koodi tekee uuden merkkijonomuuttujan vain kerran per kutsu ensimmäisen alustuskutsun jälkeen. strHex on ja pysyy aina samana (vaikka sisältö vaihtuu), samoin taulukon merkkijonot (joiden sisältö ei vaihdu).
Ja varmasti jostakin löytyy vielä nopeampi, mutta ottaen huomioon mistä on kyse, niin eipä sillä oikeasti niin väliä. Tuli vaan tehtyä lisää niitä huonoja esimerkkejä.
No kieltämättä natiivikoodiksi käännettynä tuo keskimmäinen on hidas. Pointtina nyt oli kuitenkin että hirveän paljon koodia kirjoitettu yksinkertaisen asian tekemiseen, eikä se oli perusteltavissa edes nopeudella, joka olisi muutenkin yleensä huono perustelu.
Merri kirjoitti:
Pitämällä muuttujatyypin laskujen puolella 32-bittisenä, käyttämällä Oria
Paitsi että + on nopeampi sekä tulkattuna että käännettynä. No, ero on todella marginaalinen, joten voisi sanoa että ovat käytännössä yhtä nopeita. Mutta jos nyt kerran haluat harrastaa optimointia, niin harrasta edes oikein.
Itse lähtisin mieluummin optimoimaan koodin luettavuutta.
Grez kirjoitti:
Pointtina nyt oli kuitenkin että hirveän paljon koodia kirjoitettu yksinkertaisen asian tekemiseen, eikä se oli perusteltavissa edes nopeudella, joka olisi muutenkin yleensä huono perustelu.
Pointtisi ei ole tässä tapauksessa toimiva, lue viestin kaksi ensimmäistä virkettä uudelleen.
+:n ja Or:n välillä ei ole nopeuseroa, mutta Or on tuossa tapauksessa oikeaoppisempi, tuo heti esille että nyt käsitellään bittejä eikä olla vaan ynnäämässä lukuja yhteen -> parantaa sitä koodin luettavuutta.
Kritisoit myös joidenkin toimintojen uudelleenkoodaamisia, oletettavasti huomasit siellä mm. sellaisia kuin Command ja MsgBox. Selityksenä menee, että kyseessä on Unicode-versioita. VB:n omilla ei saa esim. tietoon, että ohjelmassa yritettiin käynnistää vaikka tiedostoa "坂本真綾 - Blind Summer Fish.mp3", näkyy vaan "???? - Blind Summer Fish.mp3" ja virhehän siitä syntyy.
Sitten on nopeampia versioita, joille on oikeasti tarvettakin, erityisesti usein hyödyllisen Splitin korvike.
Möks!
Putka ei osaa :/ (mutta mod. korjasi)
Toivottavasti näistä kommenteista on jollekin hyötyä. Tarkoitus ei ole lytätä vaan lähinnä vaan ihmettelin joitain asioita.
Merri kirjoitti:
+:n ja Or:n välillä ei ole nopeuseroa
Jostain syystä kuitenkin jos kokeilen tuota ColorHex3:stasi +:n kanssa niin se on aina noin 1% nopeampi kuin Or:n kanssa. (En nyt ala arvuuttelemaan miksi ja kuten jo sanoinkin niin käytännössä ei olennaista)
Aikaisemmasta tekstistäsi sai kuitenkin käsityksen että Or olisi nopeampi joten kannattaisi sen takia käyttää sitä ennemmin. Itsekin olen samaa mieltä, että luettavuuden kannalta Or on parempi.
Tuota alkuperäistä värikoodia en vaan oikein ymmärtänyt. Mietin sitä, että jos se oli tarkoitettu "teknologiademoksi" niin silloin tuntuisi luontevalta että siinä olisi käytetty looppeja. Looppien auki kirjoittamisen voisi ehkä perustella nopeudella, mutta siihen en taas nähnyt järkeä kun koodi ei muuten ole optimaalisen nopea (joskin käännettynä nähtävästi siedettävämpi).
Ymmärrän tietysti että koodit on tarkoitettu itsellesi, mutta muiden kannalta olisi kiva jos vaikka kommentissa kerrottaisiin mikä on funktion elämäntehtävä. Eli esimerkiksi miksi saman asian tekevä funktio on parempi kuin VB:n oma. No tietysti nyt vaikka tuosta quicksplitistä pystyy nimestä päättelemään idean, joskaan itse en ole koskaan törmännyt tarpeeseen saada nopeampaa splittiä VB:hen.
Ja noita Unicode-juttuja en ollut huomannut, joten niitä en kommentoinut.
Tuhannet kiitokset Merri :) Saako kokonaista pakettia joka sisältää kaiken yhteen nidottuna mitä voi impata tuolta ?
No eikös tuolla zip-hakemistossa ole? Tai no, neljä erillistä zip-tiedostoa, mutta...
Siellä ei vielä niin kamalasti ole, että kokonaista yhtä kannattaisi tehdä.
Henkilökohtainen koodiarkistoni tosin on aikamoisen mittava, siellä vaan on niin kaamea läjä ******, että parempi vaan etten sitä sentään jakoon sellaisenaan laita.
Grez: ilmeisesti teet mittauksesi IDE:n alla, et käännetylle koodille? Käytätkö QueryPerformanceCounteria?
Looppia pidin esimerkissä tuolloin tarpeettomana, oli selvempi vain kirjoittaa "auki" kaikki mitä tapahtuu, eikä sekoittaa päätä enää loopilla. Koodia en kirjoittanut siis itselleni ollenkaan.
Sitten Or-tekstistäni, jos et vielä hoksannut, niin kyse on vaan niistä kerroista kun ajatus ei ole siirtynyt tekstimuotoon täysin siinä muodossa, kuin on ollut tarkoitus. Edellisen viestin tarkennuksen pitäisi kait olla riittävä, varsinkin kun täällä ei voi viestejä kovinkaan kauaa viestien kirjoittamisen jälkeen muokata (mikä on edelleen mielestäni varsin tyhmää, mutta minkäs teet... muilla foorumeilla saatan korjata vuosiakin vanhoja kirjoituksia ajoittain, koska niitä oikeasti joskus luetaan).
Vaikka tämä nopeusero-/-erottomuusjuttu onkin aika pitkälti aiheen vierestä, niin kommentoin silti
Merri kirjoitti:
Grez: ilmeisesti teet mittauksesi IDE:n alla, et käännetylle koodille? Käytätkö QueryPerformanceCounteria?
Tein tuon testin sekä IDEssä että käännetylle natiivikoodille. Kokeilin vielä eri optimointiasetuksiakin ja jostain kumman syystä ero oli jokaisella testillä sama. Siksi kirjoitinkin, että "se on aina noin 1% nopeampi kuin Or:n kanssa." Käytin ihan perus timeria ja funktiota taidettiin kutsua miljoona kertaa. Eli siis mittasin siis kulunutta aikaa. Tosin jos CPU-aika olisi molemmilla vaihtoehdoilla sama ja kulunut aika tietyllä tavalla korkeampi, niin sekin olisi aika mielenkiintoinen tulos.
Timer ei ole ihan paras vaihtoehto. Toisaalta jos teit kutsut peräkkäin samassa proseduurissa, niin silläkin on välillä outoja vaikutuksia aikojen mittauksessa.
Löydät jokseenkin helpon version QueryPerformanceCounterille Timings.bas-moduulista, sitä voi käyttää tyyliin:
' alusta aloittaen nollasta Timing = 0 ' testattava koodi tässä... Command1.Caption = "Suoritettiin " & Format$(Timing, "0.000000") & " sekunnissa"
Se on varsin tarkka, että välttämättä ei tarvitse edes loopata kovin paljon nähdäkseen selviä eroja, joskus ei jopa ollenkaan.
+:n ja Or:n välille en saanut mitään eroa testatessani vain niitä kahta keskenään vastakkain. Tietty vähintään puolet kului siinä vertailussa jo pelkästään for nextin pyörittämiseen.
Ja mitä väliä sillä nyt on, että aiheen vierestä mennään... keskustelua vartenhan tämä paikka kuitenkin on :)
Joo, näköjään asiaan vaikuttaa se, että missä kohdassa funktiota kutsutaan, eli todennäköisesti or ja + itsessään ei ole eri nopeuksisia. Erehdyin vaan luulemaan että eron toistuminen samansuuntaisena jokaisella ajokerralla olisi johtunut koodissa näkyvästä erosta (+ vs or), eikä satunnaistekijöistä..
Tässä tulokset performance counterin kanssa 3 kertaa exeä ajamalla
Or testi 1: 5,59400s
+ testi 1: 5,53100s
+ testi 2: 5,56300s
Or testi 2: 5,48400s
Or testi 1: 5,62500s
+ testi 1: 5,53100s
+ testi 2: 5,71900s
Or testi 2: 5,48400s
Or testi 1: 5,60900s
+ testi 1: 5,46900s
+ testi 2: 5,62500s
Or testi 2: 5,48500s
Eli keskinäiset erot pysyy joka ajokerralla samoina, ensin Or on aina nopeampi ja sitten taas + on aina nopeampi.
Mitään syytä moiseen ei pelkästään koodia katsomalla kyllä löydy, ilmeisesti asialla on tekemistä optimoinnin, prossun kakkuraan sopimisen tms. seikan kanssa.
Koodi:
http://mureakuha.com/paste/?
Niin, pidempien ajojen sijaan kannattaa keskittyä lyhyempiin ja ennen kaikkea useampiin testauksiin. Suoritusnopeuteen vaikuttaa paljon se, mitä muuta kone tekee. Minulla on niin monta palvelua sun muuta ohjelmaa taustalla päällä, että ne vaikuttavat rutkasti satunnaiseen yksittäisotokseen. Siksi napsuttelenkin nappuloita useamman kerran ja katson nopeimpia suorituksia - ja erittelen kunkin testin aina oman nappulansa taakse. Moniajomaailman kiroja tehtäessä hyvin pienten erojen vertailua.
Täytyy nostaa Merrille hattua tällaisista teoista, vaikka häneltähän tuota tasokasta, perusteltua ja ilmaista koodia muutenkin tulee foorumeille tasaiseen tahtiin. :)
Pakko tuohon +/Or-kysymykseen on nyt sanoa, että noin yksinkertaisissa tapauksissa kaiken voi todeta konekielen kautta. Yhteenlasku ja tavalliset bittioperaatiot ovat kaikki niin alkeellisia, että vievät vain yhden kellojakson melko vanhallakin prosessorilla, ja olisi outoa, jos VB jostain syystä tekisi toisen niistä jotenkin eri tavalla. Toki VB:n kanssa on helpompaa käyttää tuollaisia ajastinmittauksia, kun kääntäjältä ei (kai?) saa ulos assembly-versiota ohjelmasta (kuten esimerkiksi monilta C-kääntäjiltä), mutta tällaisessa triviaalissa tapauksessa voi jo järkevästi olettaa, että konekielessä on eroa tasan tuon käskyn verran. :) Mutkikkaammissa tapauksissa konekielen analysointi tietenkin käy hankalammaksi (silloinkin, kun se on selkokielisenä saatavilla), mutta toisaalta myös eri toteutusten erot usein muuttuvat selkeämmiksi.
Merri kirjoitti:
Niin, pidempien ajojen sijaan kannattaa keskittyä lyhyempiin ja ennen kaikkea useampiin testauksiin. Suoritusnopeuteen vaikuttaa paljon se, mitä muuta kone tekee.
Joo no sehän tuossa juuri olikin vikana, kun eliminoin alunperinkin sen, mitä kone sattuu tekemään samanaikaisesti ajamalla monta kertaa. Toki kullakin ajokerralla tulee vähän eri numerot, mutta keskinäinen järjestys pysyy samana. Eli jokin aiheuttaa selvästi nopeuseroja, mutta se ei ole tuo + vs Or.
Jollakulla on ollut jokin temppu saada assykoodia irti VB:n tuottamasta koodista, mutta hän ei siitä sen enempiä koskaan maininnut ja on nyt kadonnut ainakin minun ulottuviltani, en enää edes nimimerkkiä muista. Toisaalta minulla ei ole mahdotonta kiinnostusta ollut assyä kohtaan, on ollut kivempi tutustua VB6:n sekä Windowsin API:n mahdollisuuksiin ja rajoihin muilla tavoin.
Muoks!
Tulipahan tässä nyt mieleen, että voin toki luoda FTP-tunnuksia, jos joku haluaa myös omia koodejaan tuonne sekaan.
Tokihan minkä vaan exen saa palautettua assemblykoodiksi.
Tuossa esimerkiksi tuo 1000 satunnaista väriä luova koodi:
http://mureakuha.com/paste/?
Ja tuossa on käytännön ero Or vs +
http://grez.info/putka/PORAssy.png
Tuosta voisi sanoa, että ainakin Or:a käyttävä tuotos on kaksi assemblerkäskyä lyhempi. Toki pelkkä käskyjen määrä nyt ei taida paljoa kertoa..
Niin ja syy miksi kaksi yhteenlaskua aiheuttaa kaksi käskyä enemmän on tietenkin, että VB6 haluaa täräyttää run time errorin mikäli yhteenlaskun tuloksena on ylivuoto. Eli siis pari ylimääräistä JO rel16/32-käskyä (Jump near if overflow). Tässä rutiinissa ko. yhteenlaskuissahan ei mitenkään voi tulla ylivuotoa, mutta VB ei sitä ymmärrä.
Eli käytännössä advanced optionseista integer overflow -tarkistus pois päältä.
Toki sen saa pois, mutta en pitäisi sitä kovin järkevänä vaihtoehtona jos kyseessä on isompi ohjelmisto, koska sitä ei kuitenkaan voi määritellä funktio tai edes tiedostokohtaisesti.
Toki pienissä päräytyksissä on kätevä iskeä vaikka kaikki nuo tarkistukset veke. Array boundsien tarkistamatta jättäminen esimerkiksi tuo usein kivasti lisää tehoa, mutta toisaalta ilman sitä pystyy ihan puhtaalla VB-koodillakin aikaansaamaan puskuriylivuotoja.
Kukin tyylillään: minulla on tarkistukset aina poissa käännetyssä koodissa. Toisaalta kiinnitänkin hyvin huomiota raja-arvoihin, arvojen rajoittamiseen tietyn alueen sisään ja niin edelleen.
Aihe on jo aika vanha, joten et voi enää vastata siihen.