Light-Weight Languages and the Common Language

Download Report

Transcript Light-Weight Languages and the Common Language

Dynamic Languages and the CLI:
IronPython
Jim Hugunin
Microsoft
CLR Team
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Common Language
Infrastructure (CLI)

A virtual machine for multiple languages




International standard



Shared bytecode Intermediate Language (IL)
Common type system
Standard features JIT, AOT, GC, reflection, …
ECMA and ISO
Several open-source implementations
6 major languages in production use today


C#, VB.Net, Managed C++, J#, Eiffel and COBOL
Notably missing are Python, Perl, Scheme, …
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Missing Dynamic Languages
“The CLI is, by design, not friendly to dynamic languages.
Prototypes were built, but ran way too slowly.” – InfoWorld,
Aug. 2003
"The speed of the current system is so low as to render the current
implementation useless for anything beyond demonstration
purposes.“ – ActiveState’s report on Python for .NET

How could Microsoft have screwed up so badly that the CLR is
far worse than the JVM for dynamic languages?

Jython shows that dynamic languages can run well on the JVM
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
IronPython is…

A fast Python implementation for the CLI





Integrated with the other languages of the CLI


Compiles Python source to IL (CLI bytecode)
Includes supporting libraries (as managed code)
1.8x faster than Python-2.4 on pystone
Runs all of parrotbench at roughly the same speed as CPython
C#, VB, J#, JScript, Cobol, Eiffel, C++, …
An early prototype – version 0.6




Runs pystone and Pie-Thon/parrotbench benchmarks
All language features implemented but not well tested
A lot of library code to be written or ported
Still a few open design questions
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
pystones/second

Venerable benchmark




60
50
Simple but non-trivial




dhrystone in Python
in Lib/test/pystone.py
only benchmark that
ships with Python
70
~200 lines of code
Most basic Python ops
Very little OO
40
1.7x faster than
CPython-2.3 running
on .Net-1.1
20
30
58K
IronPython is fast

10
34K
26K
0
Python-2.1 Python-2.3 IronPython
.NET-1.1
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
pystones/second

Venerable benchmark




Simple but non-trivial




dhrystone in Python
in Lib/test/pystone.py
only benchmark that
ships with Python
70
60
50
~200 lines of code
Most basic Python ops
Very little OO
40
1.7x faster than
CPython-2.3 running
on .Net-1.1
1.8x faster than
CPython-2.4 running
on .Net-2.0beta1
20
67K
30
58K
IronPython-0.6 is fast


10
34K
38K
26K
0
Python-2.1 Python-2.3 IronPython Python-2.4 IronPython
.NET-1.1
.NET-2.0b1
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Parrotbench Benchmark



“The benchmark here is intended to make Dan
Sugalski's life difficult: there are some standard
benchmark thingies (simple random algorithms using
basic data types) but also a lot of play with odd
corners of the language definition, and Python's
extremely dynamic object model: funky descriptors,
mutable classes, that sort of thing.” – Guido van
Rossum
This is a great benchmark for alternative
implementations of Python
It only runs correctly if the implementation can
handle the range of dynamic features that make
Python what it is
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
IronPython on parrotbench

4% slower than Python-2.3 (need to update)
Python-2.3
IronPython
0
1
2
b0
3
b1
4
5
time (seconds)
b2
b3
b4
b5
6
7
b6
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
8
9
Brief parrotbench analysis

Half benchmark and half compliance test



IronPython is faster on 3 out of 6 tests


Captures the most dynamic extremes
This is a great test to have
And tied on 1 of the 6
Performance on both slow tests is dominated
by exception handling (but b5 is dominant)



throwing and catching an exception is ~3x slower
in IronPython
function calls are ~3x faster in IronPython
This is the right kind of trade-off
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Maybe the CLI can be great
for dynamic languages
“IronPython: .NET *is* a good platform for dynamic languages” –
GameDev.Net, March 2004
“Before IronPython, the common wisdom was that it was difficult to make
dynamic languages perform well on the CLR.” – Edd Dumbill, July 2004
“There was a meme floating around, a few years ago, that the CLR is
inherently unfriendly to dynamic languages. As one of the transmitters
of that meme, I'm delighted to be proved wrong.” – Jon Udell,
InfoWorld, July 2004
And many, many more of these new comments

What makes the difference?
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
IronPython Architecture
Python
Source File
or
Code
Snippet

scanner, parser, bytecode generator, support library
Bytecode is IL for the CLR – will produce native code
Support lib is written in C# instead of C
Compilation can be static or dynamic


IL
CLR
Difference is in bytecode and support library


AST
IL
Generator
Same architecture as CPython


Tokens
Python
Parser
refs

Python
Scanner
Produces .exe/.dll or dynamically load and run
IronPython is now written completely in C#


I built 3 prototypes in Python to throw away
After I understood the design I moved to C#
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
IronPython.
Objects
Compiling Factorial – to IL
def factorial(n):
if n == 1: return 1
return n * factorial(n-1)
0 LOAD_FAST 0 (n)
IL_0000: ldarg.0
3 LOAD_CONST 1 (1)
IL_0001: ldsfld object __main__::c$0$PST04000002
6 COMPARE_OP 2 (==)
IL_0006: call object IronPython…Ops::Equal(object,object)
9 JUMP_IF_FALSE 8 (to 20)
IL_000b: call bool IronPython...Ops::IsTrue(object)
IL_0010: brfalse IL_0020
12 POP_TOP
13 LOAD_CONST 1 (1)
IL_0015: ldsfld object __main__::c$0$PST04000002
16 RETURN_VALUE
IL_001a: ret
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Compiling Factorial – to x86
0 LOAD_FAST 0 (n)
3 LOAD_CONST 1 (1)
0000001b mov
00000021 mov
6 COMPARE_OP 2 (==)
00000023 call
dword ptr ds:[036E3184h]
9 JUMP_IF_FALSE 8 (to 20)
00000029
0000002b
0000002d
00000033
00000035
00000037
edi,eax
ecx,edi
dword ptr ds:[036E3084h]
edi,eax
edi,edi
00000043
mov
mov
call
mov
test
je
edx,dword ptr ds:[01B054E4h]
ecx,esi
12 POP_TOP
13 LOAD_CONST 1 (1)
00000039 mov
eax,dword ptr ds:[01B054E4h]
16 RETURN_VALUE
<pop 4 registers and ret>
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Compiling Factorial – to C#
def factorial(n):
if n == 1: return 1
return n * factorial(n-1)
public static object factorial_f1(object n) {
if (Ops.IsTrue(Ops.Equal(n, Main.c_1))) return Main.c_1;
return Ops.Multiply(n, Ops.Call(Main.factorial,
Ops.Subtract(n, Main.c_1)));
}
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Compiling Factorial – to C# v2
def factorial(n):
if n == 1: return 1
return n * factorial(n-1)
public static object factorial_f1(object n) {
if (Ops.EqualIsTrue(n, 1)) return Main.c_1;
return Ops.Multiply(n, Ops.Call(Main.factorial,
Ops.Subtract(n, Main.c_1)));
}
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Ops.EqualIsTrue
public static bool EqualIsTrue(object x, int y) {
if (x is int) return ((int)x) == y;
return IsTrue(Equal(x, y));
}

This adds a new fastpath “opcode”
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Compiling Factorial – x86 v2
0 LOAD_FAST 0 (n)
3 LOAD_CONST 1 (1)
0000001b mov
0000001d mov
ecx,esi
edx,1
6 COMPARE_OP 2 (==)
00000023 call
dword ptr ds:[036E3184h]
9 JUMP_IF_FALSE 8 (to 20)
00000028 mov
0000002a test
0000002c je
edi,eax
edi,edi
00000038
12 POP_TOP
13 LOAD_CONST 1 (1)
00000039 mov
eax,dword ptr ds:[01B054E4h]
16 RETURN_VALUE
<pop 4 registers and ret>
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Does this affect performance?

Start with a micro-benchmark
def t2():
for i in L:
if i == 1000000: break
<snip 18 identical lines>
if i == 1000000: break
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Does this affect performance?
Millions of if tests per second
80
70
60
50
40
69
30
20
10
7
11
16
Python-2.1
Python-2.3
Python-2.4
15
21
0
IronPython on IronPython on IronPython on
1.1
2.0
2.0 w/opt
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Does this affect performance?



>3x benefit on microbench
But what impact on real code?
Need to judge cost-benefit tradeoffs






What is the right general version?
Just int or int and long or something else?
Need to do all 6 comparison ops
Dual benefit that it reduces code size and increases perf in
common case
However, this reduces perf if the comparison is not with an
int because a new boxed value will need to be created on
the fly
FYI – This particular optimization is not in IronPytho0.6 because it seemed too special purpose
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
How to get good performance

Use native CLR constructs whenever possible



Create fast-paths for common cases





Python scripts to generate C# code at development time
Reflection.Emit to generate IL at runtime
Some paths might be worth writing by hand
Challenge is to figure out what merits a fast-path!
Include fall-backs to fully dynamic implementations



Ludicrously optimized machine code
But must be used creatively to match Python’s semantics
General-purpose support for less common cases
Handles Python’s fully dynamic semantics
Measure, measure, measure

100’s of small decisions not one large one
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Ease of language
experimentation

C# is a lot more fun to write than C/C++


IL is a lot more fun to write than x86/PowerPC/…


And Reflection.Emit library makes this really simple
Performance can be extremely competitive



And Visual Studio 2005 makes this really nice
Can leverage huge effort on core CLR
Ease of development plays a significant role here
Some very nice tools





CLR Debugger – source debugger for any lang + machine code
peverify – checks for safe IL and generates clear easy to
understand errors for buggy compiler generated IL
ildasm/ilasm – nice command-line and GUI IL tools
Lutz Roeder’s Reflector – a very nice way to inspect assemblies
Visual Studio 2005
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Integration is more important
than performance

Demo
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
A few open design questions







How many kinds of strings? i.e. difference between
unicode and ascii?
How to handle locals() and sys._getframe().f_locals?
How to interoperate with other dynamic languages?
How to most effectively expose Python code to other
CLR languages
What about unboxed ints like smalltalk and some
schemes?
How to support continuations?
…
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved
Conclusions


The CLI is a great platform for language development
Ease of development is key

C# is a lot more fun to write than C/C++


IL is a lot more fun to write than x86/PowerPC/…


And Reflection.Emit library makes this really simple
Performance can be extremely competitive


And Visual Studio 2005 makes this really nice
Ease of development plays a significant role here
Best effort to date for language interoperability


6 major languages in production today
Easy interoperability among these

Tools and libraries are powerful and fun

Why not leverage hundreds of man-years of VM development?
Copyright (c) 2004 Microsoft Corporation, All Rights Reserved