RychlostGraalVM
Z Denik
Řádka 3: | Řádka 3: | ||
Objektivně měřit něco takového je přetěžký úkol. Téměř každý jazyk poskytuje dodatečné vestavěné operace, které již nejsou implementovány v daném jazyce, ale volají do vysoce optimalizované knihovny napsané v Céčku či assembleru. Její autoři si pak dávají dost záležet, aby zrovna ten jejich výpočet byl co nejrychlejší. Tudíž porovnávat rychlost jazyků na základě takovýchto specializovaných vychytávek nedává moc smysl. Na druhou stranu každý řádný programovací jazyk musí být turingovský úplný (musí podporovat obecné programovací konstrukce jako '''if''', '''for''' a '''while'''), a tak navrhuji, abychom ''turingovskou rychlost'' jazyka měřili na základě obecného výpočtu, který pokud možno bude co nejméně využívat zabudovaných zkratek. To je samozřejmě těžké. Pokud se takový obecný výpočet stane známým, tak na něj začnou tvůrci jazyka cílit, speciálně optimalizovat a bude opět po nezávislosti. Tomu lze asi nejlépe zabránit tím, že si člověk napíše svůj vlastní algoritmus a provede si měření sám. Tak jako jsem to já udělal s [http://github.com/jtulach/sieve Eratosthénovým sítem na výpočet prvočísel]. | Objektivně měřit něco takového je přetěžký úkol. Téměř každý jazyk poskytuje dodatečné vestavěné operace, které již nejsou implementovány v daném jazyce, ale volají do vysoce optimalizované knihovny napsané v Céčku či assembleru. Její autoři si pak dávají dost záležet, aby zrovna ten jejich výpočet byl co nejrychlejší. Tudíž porovnávat rychlost jazyků na základě takovýchto specializovaných vychytávek nedává moc smysl. Na druhou stranu každý řádný programovací jazyk musí být turingovský úplný (musí podporovat obecné programovací konstrukce jako '''if''', '''for''' a '''while'''), a tak navrhuji, abychom ''turingovskou rychlost'' jazyka měřili na základě obecného výpočtu, který pokud možno bude co nejméně využívat zabudovaných zkratek. To je samozřejmě těžké. Pokud se takový obecný výpočet stane známým, tak na něj začnou tvůrci jazyka cílit, speciálně optimalizovat a bude opět po nezávislosti. Tomu lze asi nejlépe zabránit tím, že si člověk napíše svůj vlastní algoritmus a provede si měření sám. Tak jako jsem to já udělal s [http://github.com/jtulach/sieve Eratosthénovým sítem na výpočet prvočísel]. | ||
- | Když jsem se k ''OracleLabs'' před pár lety přidal, moji kolegové hrdě tvrdili, že jejich implementace '''Ruby''' je desetkrát rychlejší než jakákoli jiná. ''"To určitě!"'' pomyslel jsem si. ''"Možná je rychlá na nějakém speciálním příkládku, ale jinak to přeci není možné"'' a řekl jsem si, že to vyzkouším. Chvíli jsem přemýšlel o nějakém vhodném příkladu a Eratosthénovo síto mi přišlo ideální. Je to výpočet, který může běžet libovolně dlouho (dokud nedojdou prvočísla), který provádí aritmetické operace a který (v mé verzi) alokuje objekty do spojového seznamu. Vcelku vhodný kandidát na měření ''turingovské rychlosti'', řekl jsem si a začal psát svůj první program v | + | Když jsem se k ''OracleLabs'' před pár lety přidal, moji kolegové hrdě tvrdili, že jejich implementace '''Ruby''' je desetkrát rychlejší než jakákoli jiná. ''"To určitě!"'' pomyslel jsem si. ''"Možná je rychlá na nějakém speciálním příkládku, ale jinak to přeci není možné"'' a řekl jsem si, že to vyzkouším. Chvíli jsem přemýšlel o nějakém vhodném příkladu a Eratosthénovo síto mi přišlo ideální. Je to výpočet, který může běžet libovolně dlouho (dokud nedojdou prvočísla), který provádí aritmetické operace a který (v mé verzi) alokuje objekty do spojového seznamu. Vcelku vhodný kandidát na měření ''turingovské rychlosti'', řekl jsem si a začal psát svůj [https://github.com/jtulach/sieve/blob/ccca0c8a7c30b36234d2f2196581aa861d0ad428/ruby/sieve.rb první program v Ruby]: |
- | < | + | <pre> |
- | def + | + | class Natural |
- | </ | + | def initialize |
+ | @x = 1 | ||
+ | end | ||
+ | |||
+ | def next | ||
+ | @x += 1 | ||
+ | end | ||
+ | end | ||
+ | |||
+ | class Filter | ||
+ | attr_reader :number | ||
+ | attr_accessor :next | ||
+ | |||
+ | def initialize(number) | ||
+ | @number = number | ||
+ | @next = nil | ||
+ | @last = self | ||
+ | end | ||
+ | |||
+ | def acceptAndAdd(n) | ||
+ | filter = self | ||
+ | upto = Math.sqrt(n) | ||
+ | while filter | ||
+ | if n % filter.number == 0 | ||
+ | return false | ||
+ | end | ||
+ | if filter.number > upto | ||
+ | break | ||
+ | end | ||
+ | filter = filter.next | ||
+ | end | ||
+ | filter = Filter.new(n) | ||
+ | @last.next = filter | ||
+ | @last = filter | ||
+ | true | ||
+ | end | ||
+ | end | ||
+ | |||
+ | class Primes | ||
+ | def initialize(natural) | ||
+ | @natural = natural | ||
+ | @filter = nil | ||
+ | end | ||
+ | |||
+ | def next | ||
+ | while true | ||
+ | n = @natural.next | ||
+ | if @filter == nil | ||
+ | @filter = Filter.new(n) | ||
+ | return n | ||
+ | end | ||
+ | if @filter.acceptAndAdd(n) | ||
+ | return n | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | |||
+ | def ms(start) | ||
+ | ((Time.now - start) * 1000).floor | ||
+ | end | ||
+ | |||
+ | def fewthousands | ||
+ | natural = Natural.new | ||
+ | primes = Primes.new(natural) | ||
+ | |||
+ | start = Time.now | ||
+ | cnt = 0 | ||
+ | prntCnt = 97 | ||
+ | begin | ||
+ | res = primes.next | ||
+ | cnt += 1 | ||
+ | if cnt % prntCnt == 0 | ||
+ | puts "Computed #{cnt} primes in #{ms(start)} ms. Last one is #{res}." | ||
+ | prntCnt = prntCnt * 2 | ||
+ | end | ||
+ | end while cnt < 100000 | ||
+ | ms(start) | ||
+ | end | ||
+ | |||
+ | puts "Ready!" | ||
+ | |||
+ | count = -1 | ||
+ | if ARGV.length == 1 | ||
+ | then | ||
+ | count = ARGV[0].to_i | ||
+ | end | ||
+ | |||
+ | while count != 0 | ||
+ | puts "Hundred thousand prime numbers in #{fewthousands} ms" | ||
+ | count = count - 1 | ||
+ | end | ||
+ | </pre> |
Verze z 20. 4. 2018, 10:44
Jsou opravdu GraalVM jazyky tak rychlé, jak o sobě tvrdí? A jak vůbec měřit rychlost jazyka?
Objektivně měřit něco takového je přetěžký úkol. Téměř každý jazyk poskytuje dodatečné vestavěné operace, které již nejsou implementovány v daném jazyce, ale volají do vysoce optimalizované knihovny napsané v Céčku či assembleru. Její autoři si pak dávají dost záležet, aby zrovna ten jejich výpočet byl co nejrychlejší. Tudíž porovnávat rychlost jazyků na základě takovýchto specializovaných vychytávek nedává moc smysl. Na druhou stranu každý řádný programovací jazyk musí být turingovský úplný (musí podporovat obecné programovací konstrukce jako if, for a while), a tak navrhuji, abychom turingovskou rychlost jazyka měřili na základě obecného výpočtu, který pokud možno bude co nejméně využívat zabudovaných zkratek. To je samozřejmě těžké. Pokud se takový obecný výpočet stane známým, tak na něj začnou tvůrci jazyka cílit, speciálně optimalizovat a bude opět po nezávislosti. Tomu lze asi nejlépe zabránit tím, že si člověk napíše svůj vlastní algoritmus a provede si měření sám. Tak jako jsem to já udělal s Eratosthénovým sítem na výpočet prvočísel.
Když jsem se k OracleLabs před pár lety přidal, moji kolegové hrdě tvrdili, že jejich implementace Ruby je desetkrát rychlejší než jakákoli jiná. "To určitě!" pomyslel jsem si. "Možná je rychlá na nějakém speciálním příkládku, ale jinak to přeci není možné" a řekl jsem si, že to vyzkouším. Chvíli jsem přemýšlel o nějakém vhodném příkladu a Eratosthénovo síto mi přišlo ideální. Je to výpočet, který může běžet libovolně dlouho (dokud nedojdou prvočísla), který provádí aritmetické operace a který (v mé verzi) alokuje objekty do spojového seznamu. Vcelku vhodný kandidát na měření turingovské rychlosti, řekl jsem si a začal psát svůj první program v Ruby:
class Natural def initialize @x = 1 end def next @x += 1 end end class Filter attr_reader :number attr_accessor :next def initialize(number) @number = number @next = nil @last = self end def acceptAndAdd(n) filter = self upto = Math.sqrt(n) while filter if n % filter.number == 0 return false end if filter.number > upto break end filter = filter.next end filter = Filter.new(n) @last.next = filter @last = filter true end end class Primes def initialize(natural) @natural = natural @filter = nil end def next while true n = @natural.next if @filter == nil @filter = Filter.new(n) return n end if @filter.acceptAndAdd(n) return n end end end end def ms(start) ((Time.now - start) * 1000).floor end def fewthousands natural = Natural.new primes = Primes.new(natural) start = Time.now cnt = 0 prntCnt = 97 begin res = primes.next cnt += 1 if cnt % prntCnt == 0 puts "Computed #{cnt} primes in #{ms(start)} ms. Last one is #{res}." prntCnt = prntCnt * 2 end end while cnt < 100000 ms(start) end puts "Ready!" count = -1 if ARGV.length == 1 then count = ARGV[0].to_i end while count != 0 puts "Hundred thousand prime numbers in #{fewthousands} ms" count = count - 1 end