1 [h1]
EN: Performance
JA: 性能

2 [p]
EN: Even though most benchmarks aren’t worth the pixels they’re printed on, people
seem to like them, so here’s a few:
JA: ほとんどのベンチマークは、表示に使うピクセルほどの価値もありませんが、人々は好きなようなので、いくつか示します。

3 [h3]
EN: Method Call
JA: メソッド呼び出し

4 [th]
EN: wren
JA: wren

5 [td]
EN: 0.12s 
JA: 0.12s 

6 [th]
EN: luajit (-joff)
JA: luajit (-joff)

7 [td]
EN: 0.16s 
JA: 0.16s 

8 [th]
EN: ruby
JA: ruby

9 [td]
EN: 0.20s 
JA: 0.20s 

10 [th]
EN: lua
JA: lua

11 [td]
EN: 0.35s 
JA: 0.35s 

12 [th]
EN: python3
JA: python3

13 [td]
EN: 0.78s 
JA: 0.78s 

14 [th]
EN: python
JA: python

15 [td]
EN: 0.85s 
JA: 0.85s 

16 [h3]
EN: DeltaBlue
JA: DeltaBlue

17 [th]
EN: wren
JA: wren

18 [td]
EN: 0.13s 
JA: 0.13s 

19 [th]
EN: python3
JA: python3

20 [td]
EN: 0.48s 
JA: 0.48s 

21 [th]
EN: python
JA: python

22 [td]
EN: 0.57s 
JA: 0.57s 

23 [h3]
EN: Binary Trees
JA: 二分木

24 [th]
EN: luajit (-joff)
JA: luajit (-joff)

25 [td]
EN: 0.11s 
JA: 0.11s 

26 [th]
EN: wren
JA: wren

27 [td]
EN: 0.22s 
JA: 0.22s 

28 [th]
EN: ruby
JA: ruby

29 [td]
EN: 0.24s 
JA: 0.24s 

30 [th]
EN: python
JA: python

31 [td]
EN: 0.37s 
JA: 0.37s 

32 [th]
EN: python3
JA: python3

33 [td]
EN: 0.38s 
JA: 0.38s 

34 [th]
EN: lua
JA: lua

35 [td]
EN: 0.52s 
JA: 0.52s 

36 [h3]
EN: Recursive Fibonacci
JA: 再帰的なフィボナッチ計算

37 [th]
EN: luajit (-joff)
JA: luajit (-joff)

38 [td]
EN: 0.10s 
JA: 0.10s 

39 [th]
EN: wren
JA: wren

40 [td]
EN: 0.20s 
JA: 0.20s 

41 [th]
EN: ruby
JA: ruby

42 [td]
EN: 0.22s 
JA: 0.22s 

43 [th]
EN: lua
JA: lua

44 [td]
EN: 0.28s 
JA: 0.28s 

45 [th]
EN: python
JA: python

46 [td]
EN: 0.51s 
JA: 0.51s 

47 [th]
EN: python3
JA: python3

48 [td]
EN: 0.57s 
JA: 0.57s 

49 [p]
EN: Shorter bars are better. Each benchmark is run ten times and the best time
is kept. It only measures the time taken to execute the benchmarked code
itself, not interpreter startup.
JA: 棒が短いほど高速です。各ベンチマークは10回実行し、最も速かった時間を採用します。測定するのは、ベンチマーク対象のコード自身を実行する時間だけで、インタープリターの起動時間は含みません。

50 [p]
EN: These were run on my MacBook Pro 2.3 GHz Intel Core i7 with 16 GB of 1,600 MHz
DDR3 RAM. Tested against Lua 5.2.3, LuaJIT 2.0.2, Python 2.7.5, Python 3.3.4,
ruby 2.0.0p247. LuaJIT is run with the JIT disabled (i.e. in bytecode
interpreter mode) since I want to support platforms where JIT-compilation is
disallowed. LuaJIT with the JIT enabled is much faster than all of the other
languages benchmarked, including Wren, because Mike Pall is a robot from the
future.
JA: 私のMacBook Pro、2.3 GHz Intel Core i7、16 GBの1,600 MHz DDR3 RAMで実行しました。比較対象はLua 5.2.3、LuaJIT 2.0.2、Python 2.7.5、Python 3.3.4、ruby 2.0.0p247です。JITコンパイルを許可しないプラットフォームもサポートしたいので、LuaJITはJITを無効にして、バイトコードインタープリターモードで実行しています。JITを有効にしたLuaJITは、Wrenも含め、ここで測定したほかのすべての言語よりはるかに高速です。Mike Pallは、未来から来たロボットなのです。

51 [p]
EN: The benchmark harness and programs are
here.
JA: ベンチマークの実行基盤とプログラムは、こちらにあります。

52 [h2]
EN: Why is Wren fast? #
JA: Wrenが高速なのはなぜか？ #

53 [p]
EN: Languages come in four rough performance buckets, from slowest to fastest:
JA: 言語の性能は、大まかに四つのグループに分かれます。遅いものから速いものへ並べると、次のとおりです。

54 [li]
EN: 
Tree-walk interpreters: Ruby 1.8.7 and earlier, Io, that
    interpreter you wrote for a class in college.

JA: 構文木をたどるインタープリター：Ruby 1.8.7以前、Io、大学の授業で作ったインタープリター。

55 [li]
EN: 
Bytecode interpreters: CPython,
    Ruby 1.9 and later, Lua, early JavaScript VMs.

JA: バイトコードインタープリター：CPython、Ruby 1.9以降、Lua、初期のJavaScript VM。

56 [li]
EN: 
JIT compiled dynamically typed languages: Modern JavaScript VMs,
    LuaJIT, PyPy, some Lisp/Scheme implementations.

JA: JITコンパイルする動的型付け言語：現代のJavaScript VM、LuaJIT、PyPy、一部のLisp/Scheme実装。

57 [li]
EN: 
Statically typed languages: C, C++, Java, C#, Haskell, etc.

JA: 静的型付け言語：C、C++、Java、C#、Haskellなど。

58 [p]
EN: Most languages in the first bucket aren’t suitable for production use. (Servers
are one exception, because you can throw more hardware at a slow language
there.) Languages in the second bucket are fast enough for many use cases, even
on client hardware, as the success of the listed languages shows. Languages in
the third bucket are quite fast, but their implementations are breathtakingly
complex, often rivaling that of compilers for statically-typed languages.
JA: 最初のグループの言語は、ほとんどが本番利用に適していません。（サーバーは例外の一つです。遅い言語へ、より多くのハードウェアを投入できるからです。）二つ目のグループは、挙げた言語の成功が示すように、クライアントのハードウェアでも、多くの用途に十分な速度があります。三つ目のグループは、かなり高速ですが、その実装は驚くほど複雑で、静的型付け言語のコンパイラーに匹敵することもよくあります。

59 [p]
EN: Wren is in the second bucket. If you want a simple implementation that’s fast
enough for real use, this is the sweet spot. In addition, Wren has a few tricks
up its sleeve:
JA: Wrenは、二つ目のグループです。実用に十分な速度を持つ単純な実装が欲しいなら、ここが適したところです。さらに、Wrenには、いくつかの工夫があります。

60 [h3]
EN: A compact value representation #
JA: コンパクトな値の表現 #

61 [p]
EN: A core piece of a dynamic language implementation is the data structure used
for variables. It needs to be able to store (or reference) a value of any type,
while also being as compact as possible. Wren uses a technique called NaN
tagging for this.
JA: 動的言語の実装で中心になるのは、変数に使うデータ構造です。どの型の値でも保存、または参照でき、それと同時に、できるだけコンパクトである必要があります。Wrenは、このためにNaNタグ付けという手法を使います。

62 [p]
EN: All values are stored internally in Wren as small, eight-byte double-precision
floats. Since that is also Wren’s number type, in order to do arithmetic, no
conversion is needed before the “raw” number can be accessed: a value holding a
number is a valid double. This keeps arithmetic fast.
JA: Wrenでは、すべての値を内部で、小さな8バイトの倍精度浮動小数点数として保存します。これはWrenの数値型でもあるので、算術演算では、「生の」数値へアクセスする前の変換が不要です。数値を保持する値は、有効なdoubleそのものです。これで、算術演算を高速に保ちます。

63 [p]
EN: To store values of other types, it turns out there’s a ton of unused bits in a
NaN double. You can stuff a pointer for heap-allocated objects, with room left
over for special values like true, false, and null. This means numbers,
bools, and null are unboxed. It also means an entire value is only eight bytes,
the native word size on 64-bit machines. Smaller = faster when you take into
account CPU caching and the cost of passing values around.
JA: ほかの型の値を保存するために使える、未使用のビットが、NaNのdoubleには大量にあります。そこへ、ヒープに割り当てたオブジェクトのポインターを格納でき、true、false、nullなどの特別な値に使う余地も残ります。つまり、数値、真偽値、nullはボックス化しません。また、値全体はわずか8バイト、64ビットマシンのネイティブなワードサイズです。CPUキャッシュと、値を受け渡すコストを考えると、小さいほど高速です。

64 [h3]
EN: Fixed object layout #
JA: 固定したオブジェクト配置 #

65 [p]
EN: Most dynamic languages treat objects as loose bags of named properties. You can
freely add and remove properties from an object after you’ve created it.
Languages like Lua and JavaScript don’t even have a well-defined concept of a
“type” of object.
JA: ほとんどの動的言語は、オブジェクトを、名前付きプロパティーの緩い集まりとして扱います。作成後も、自由にプロパティーを追加・削除できます。LuaやJavaScriptなどには、オブジェクトの「型」という明確な概念すらありません。

66 [p]
EN: Wren is strictly class-based. Every object is an instance of a class. Classes
in turn have a well-defined declarative syntax, and cannot be imperatively
modified. In addition, fields in Wren are private to the class—they can
only be accessed from methods defined directly on that class.
JA: Wrenは、厳密にクラスを基礎とします。すべてのオブジェクトは、クラスのインスタンスです。クラスには、明確な宣言構文があり、命令的には変更できません。さらに、Wrenのフィールドは、クラスに対して非公開であり、そのクラスへ直接定義したメソッドからしかアクセスできません。

67 [p]
EN: Put all of that together and it means you can determine at compile time
exactly how many fields an object has and what they are. In other languages,
when you create an object, you allocate some initial memory for it, but that
may have to be reallocated multiple times as fields are added and the object
grows. Wren just does a single allocation up front for exactly the right number
of fields.
JA: これらを合わせると、コンパイル時に、オブジェクトのフィールドが何個あり、それぞれ何かを、正確に決められます。ほかの言語では、作成時に初期メモリーを割り当てますが、フィールドの追加でオブジェクトが大きくなると、何度も再割り当てが必要になる場合があります。Wrenは、最初に一度だけ、正確なフィールド数に合う領域を割り当てます。

68 [p]
EN: Likewise, when you access a field in other languages, the interpreter has to
look it up by name in a hash table in the object, and then maybe walk its
inheritance chain if it can’t find it. It must do this every time since fields
may be added freely. In Wren, field access is just accessing a slot in the
instance by an offset known at compile time: it’s just adding a few pointers.
JA: 同様に、ほかの言語でフィールドへアクセスするとき、インタープリターは、オブジェクト内のハッシュテーブルで名前を探し、見つからなければ、継承の連鎖をたどる場合があります。フィールドは自由に追加できるので、毎回行う必要があります。Wrenでは、コンパイル時に分かるオフセットを使い、インスタンスのスロットへアクセスするだけです。わずかなポインターの加算で済みます。

69 [h3]
EN: Copy-down inheritance #
JA: メソッドをコピーする継承 #

70 [p]
EN: When you call a method on an object, the method must be located. It could be
defined directly on the object’s class, or it may be inheriting it from some
superclass. This means that in the worst case, you may have to walk the
inheritance chain to find it.
JA: オブジェクトのメソッドを呼び出すには、そのメソッドを見つける必要があります。オブジェクトのクラスへ直接定義したものかもしれませんし、親クラスから継承したものかもしれません。そのため、最悪の場合、見つけるために継承の連鎖をたどる必要があります。

71 [p]
EN: Advanced implementations do very smart things to optimize this, but it’s made
more difficult by the mutable nature of the underlying language: if you can add
new methods to existing classes freely or change the inheritance hierarchy, the
lookup for a given method may actually change over time. You have to check for
that which costs CPU cycles.
JA: 高度な実装は、これを最適化する巧妙な処理を行いますが、言語自身が変更可能であることが難しさを増します。既存クラスへ自由にメソッドを追加したり、継承階層を変更したりできると、あるメソッドの探索結果が時間とともに変わる場合があります。それを確認する必要があり、CPUサイクルを消費します。

72 [p]
EN: Wren’s inheritance hierarchy is static and fixed at class definition time. This
means that we can copy down all inherited methods in the subclass when it’s
created since we know those will never change. Method dispatch then just
requires locating the method in the class of the receiver.
JA: Wrenの継承階層は静的であり、クラス定義時に固定します。継承したメソッドは、今後変わらないと分かるので、子クラスを作るとき、すべてをそこへコピーできます。そのため、メソッドのディスパッチは、レシーバーのクラス内でメソッドを探すだけで済みます。

73 [h3]
EN: Method signatures #
JA: メソッドのシグネチャ #

74 [p]
EN: Wren supports overloading by arity using its concept of signatures. This makes
the language more expressive, but also faster. When a method is called, we look
it up on the receiver’s class. If we succeed in finding it, we also know it has
the right number of parameters.
JA: Wrenは、シグネチャの概念を使い、引数の個数によるオーバーロードをサポートします。これにより、言語の表現力と速度が増します。メソッドを呼び出すとき、レシーバーのクラスで探します。見つかれば、そのメソッドの引数の数も正しいと分かります。

75 [p]
EN: This lets Wren avoid the extra checking most languages need to do at runtime to
handle too few or too many arguments being passed to a method. In Wren, it’s not
syntactically possible to call a method with the wrong number of arguments.
JA: これにより、多くの言語で、メソッドへ渡した引数が少なすぎたり多すぎたりしないか実行時に行う、追加の確認を省けます。Wrenでは、誤った個数の引数でメソッドを呼び出すことは、構文上できません。

76 [h3]
EN: Computed gotos #
JA: 計算型goto #

77 [p]
EN: On compilers that support it, Wren’s core bytecode interpreter loop uses
something called computed gotos. The hot core of a bytecode
interpreter is effectively a giant switch on the instruction being executed.
JA: サポートするコンパイラーでは、Wrenのバイトコードインタープリターの主要ループに、計算型gotoというものを使います。バイトコードインタープリターの頻繁に実行する中心部分は、実質的には、実行する命令を対象とした巨大なswitchです。

78 [p]
EN: Doing that using an actual switch confounds the CPU’s branch
predictor—there is basically a single branch point for the entire
interpreter. That quickly saturates the predictor and it just gets confused and
fails to predict anything, which leads to more CPU stalls and pipeline flushes.
JA: これを実際のswitchで行うと、CPUの分岐予測器を混乱させます。インタープリター全体に、事実上一つの分岐点しかないからです。予測器はすぐに飽和し、混乱して何も予測できなくなり、CPUの停止やパイプラインのフラッシュが増えます。

79 [p]
EN: Using computed gotos gives you a separate branch point at the end of each
instruction. Each gets its own branch prediction, which often succeeds since
some instruction pairs are more common than others. In my rough testing, this
makes a 5-10% performance difference.
JA: 計算型gotoを使うと、各命令の末尾に、別々の分岐点ができます。それぞれが独自の分岐予測を使え、ほかより多い命令の組み合わせがあるため、予測が成功することがよくあります。私の大まかなテストでは、性能に5～10%の差が出ます。

80 [h3]
EN: A single-pass compiler #
JA: 単一パスのコンパイラー #

81 [p]
EN: Compile time is a relatively small component of a language’s performance: code
only has to be compiled once but a given line of code may be run many times.
However, fast compilation helps with startup speed—the time it takes to
get anything up and running. For that, Wren’s compiler is quite fast.
JA: コンパイル時間は、言語の性能の比較的小さな部分です。コードは一度コンパイルすれば済みますが、一行のコードを何度も実行する場合があります。しかし、コンパイルが速いと、何かを起動して動かすまでの起動時間に役立ちます。その点で、Wrenのコンパイラーはかなり高速です。

82 [p]
EN: It’s modeled after Lua’s compiler. Instead of tokenizing and then parsing to
create a bunch of AST structures which are then consumed and deallocated by
later phases, it emits code directly during parsing. This means it does minimal
memory allocation during a parse and has very little overhead.
JA: Luaのコンパイラーを手本にしています。トークン化してから解析し、後の段階で消費・解放する大量のAST構造を作る代わりに、解析中に直接コードを出力します。そのため、解析中のメモリー割り当ては最小限で、余分な負担がほとんどありません。

83 [h2]
EN: Why don’t other languages do this? #
JA: ほかの言語が同じことをしないのはなぜか？ #

84 [p]
EN: Most of Wren’s performance comes from language design decisions. While it’s
dynamically typed and dispatched, classes are relatively statically
defined. That makes a lot of things much easier. Other languages have a much
more mutable object model, and cannot change that without breaking lots of
existing code.
JA: Wrenの性能の多くは、言語設計の判断から生まれます。型付けとディスパッチは動的ですが、クラスの定義は比較的静的です。そのため、多くのことが容易になります。ほかの言語は、オブジェクトのモデルがはるかに変更可能であり、大量の既存コードを壊さずに変えることはできません。

85 [p]
EN: Wren’s closest sibling, by far, is Lua. Lua is more dynamic than Wren which
makes its job harder. Lua also tries very hard to be compatible across a wide
range of hardware and compilers. If you have a C89 compiler for it, odds are
very good that you can run Lua on it.
JA: Wrenに最も近い仲間は、圧倒的にLuaです。LuaはWrenより動的であり、その分、実装が難しくなります。また、Luaは、幅広いハードウェアとコンパイラーとの互換性を保つため、非常に努力しています。C89コンパイラーがあれば、そこでLuaを動かせる可能性は、とても高いでしょう。

86 [p]
EN: Wren cares about compatibility, but it requires C99 or C++98 and IEEE double
precision floats. That may exclude some edge case hardware, but makes things
like NaN tagging, computed gotos, and some other tricks possible.
JA: Wrenも互換性を重視しますが、C99またはC++98と、IEEEの倍精度浮動小数点数を必要とします。そのため、一部の特殊なハードウェアを除外するかもしれませんが、NaNタグ付け、計算型goto、ほかのいくつかの工夫を使えます。
