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 请问为什么我配置IPsec后PC1 ping不通 PC2,抓包出来数据包也并没有被加密
  • ¥200 求博主教我搞定neo4j简易问答系统,有偿
  • ¥15 nginx的使用与作用
  • ¥100 关于#VijeoCitect#的问题,如何解决?(标签-ar|关键词-数据类型)
  • ¥15 一个矿井排水监控系统的plc梯形图,求各程序段都是什么意思
  • ¥15 ensp路由器启动不了一直报#
  • ¥50 安卓10如何在没有root权限的情况下设置开机自动启动指定app?
  • ¥15 ats2837 spi2从机的代码
  • ¥200 wsl2 vllm qwen1.5部署问题
  • ¥100 有偿求数字经济对经贸的影响机制的一个数学模型,弄不出来已经快要碎掉了