dongxiangchan0743 2017-12-14 10:02
浏览 53
已采纳

Ocaml表现vs

I'm trying to implement utf8 decoding in Ocaml as a learning project. To check the performance I'm benchmarking against the go standard library.

This is the go code:

package main

import (
    "fmt"
    "time"
    "unicode/utf8"
)

func main() {
    start := time.Now()

    for i := 0; i < 1000000000; i++ {
        utf8.ValidRune(23450)
    }

    elapsed := time.Since(start)
    fmt.Println(elapsed)
}

When I run it, I get:

go build b.go
./b
344.979492ms

I decided to write an equivalent in ocaml:

let min = 0x0000
let max = 0x10FFFF

let surrogateMin = 0xD800
let surrogateMax = 0xDFFF

let validUchar c =
  if (0 <= c && c < surrogateMin) then
    true
  else if (surrogateMax < c && c <= max) then
    true
  else
    false

let time f x =
    let t = Sys.time () in
    let _ = f x in
    let t2 = Sys.time () in
    let diff = (t2 -. t) *. 1000. in
    print_endline ((string_of_float diff) ^ "ms")


let test () =
  for i = 0 to 1000000000 do
    let _ = validUchar 23450 in
    ()
  done

let () = time test ()

Output:

ocamlopt bMl.ml -o bMl
./bMl
2041.075ms

The ocaml equivalent basically copies the implementation of the go stdlib from https://golang.org/src/unicode/utf8/utf8.go#L517

Why is the ocaml code so much slower?

  • 写回答

2条回答 默认 最新

  • dongranding3909 2017-12-16 04:40
    关注

    As observed you should be using Unix.gettimeofday to measure wallclock time. You can use Sys.opaque_identity however to prevent OCaml from optimizing useless operations away, and you can use ignore to 'return unit' instead of the usual value of an expression. Altogether:

    let time f x =
      let t = Unix.gettimeofday () in
      ignore (Sys.opaque_identity (f x));
      let t2 = Unix.gettimeofday () in
      ...
    
    let test () =
      for i = 1 to 1_000_000_000 do
        ignore (Sys.opaque_identity (validUchar 23450));            
      done
    

    Note the i = 1, which you want if you want exactly one billion iterations (a figure I couldn't tell was one billion before adding the underscores, which OCaml allows). Previously you were measuring one billion plus 1 iterations. Not that that was the difference.

    Your verbose definition of validUchar did not benefit its performance any. Please write a microbenchmark and confirm that.

    Finally, after making the changes suggested above and writing your validUchar in a more natural manner, I get an OCaml runtime that's identical to the Go runtime ... after adding -O3 to the ocamlopt arguments. And it's easy to confirm that this isn't due to the compiler 'optimizing the operations away' -- commenting out the f x call in time results in runtimes of 0 or near-0 values like 1.19e-06.

    Don't be discouraged by the responses you got to this question. But do expect that any kind of "why does this benchmark have this result?" question to a programming forum will be answered similarly.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测