Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Koodia jaossa vielä VB6:sta kiinnostuneille

Sivun loppuun

Merri [16.10.2008 21:50:52]

#

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.

Grez [17.10.2008 09:54:50]

#

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.

Merri [17.10.2008 18:20:46]

#

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ä.

Grez [17.10.2008 21:57:51]

#

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.

Merri [17.10.2008 22:31:43]

#

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)

Grez [17.10.2008 22:54:44]

#

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.

rautamiekka [20.10.2008 21:04:37]

#

Tuhannet kiitokset Merri :) Saako kokonaista pakettia joka sisältää kaiken yhteen nidottuna mitä voi impata tuolta ?

Grez [20.10.2008 21:07:13]

#

No eikös tuolla zip-hakemistossa ole? Tai no, neljä erillistä zip-tiedostoa, mutta...

Merri [21.10.2008 18:22:16]

#

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).

Grez [21.10.2008 18:48:26]

#

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.

Merri [21.10.2008 19:28:07]

#

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 :)

Grez [21.10.2008 20:23:56]

#

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/?eb235683050439903e1f8a9d2625b3f1

Merri [21.10.2008 21:06:31]

#

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.

Metabolix [21.10.2008 21:18:23]

#

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.

Grez [21.10.2008 21:35:16]

#

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.

Merri [21.10.2008 21:39:01]

#

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.

Grez [21.10.2008 22:03:17]

#

Tokihan minkä vaan exen saa palautettua assemblykoodiksi.

Tuossa esimerkiksi tuo 1000 satunnaista väriä luova koodi:
http://mureakuha.com/paste/?5b039f3d3f43c241df2e4ed3f31febe9

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..

Grez [21.10.2008 23:14:16]

#

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ä.

Merri [21.10.2008 23:31:02]

#

Eli käytännössä advanced optionseista integer overflow -tarkistus pois päältä.

Grez [21.10.2008 23:38:02]

#

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.

Merri [21.10.2008 23:50:25]

#

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.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta