[pypy-svn] extradoc extradoc: more figureyfication

cfbolz commits-noreply at bitbucket.org
Thu Mar 24 15:19:40 CET 2011


Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: extradoc
Changeset: r3394:901a8645f1ba
Date: 2011-03-24 15:19 +0100
http://bitbucket.org/pypy/extradoc/changeset/901a8645f1ba/

Log:	more figureyfication

diff --git a/talk/icooolps2011/code/trace2.tex b/talk/icooolps2011/code/trace2.tex
new file mode 100644
--- /dev/null
+++ b/talk/icooolps2011/code/trace2.tex
@@ -0,0 +1,33 @@
+\begin{Verbatim}
+# inst.getattr("a")
+map1 = inst.map
+guard(map1 == 0xb74af4a8)
+index1 = Map.getindex(map1, "a")
+guard(index1 != -1)
+storage1 = inst.storage
+result1 = storage1[index1]
+
+# inst.getattr("b")
+map2 = inst.map
+guard(map2 == 0xb74af4a8)
+index2 = Map.getindex(map2, "b")
+guard(index2 == -1)
+cls1 = inst.cls
+methods1 = cls.methods
+result2 = dict.get(methods1, "b")
+guard(result2 is not None)
+v2 = result1 + result2
+
+# inst.getattr("c")
+map3 = inst.map
+guard(map3 == 0xb74af4a8)
+index3 = Map.getindex(map3, "c")
+guard(index3 == -1)
+cls1 = inst.cls
+methods2 = cls.methods
+result3 = dict.get(methods2, "c")
+guard(result3 is not None)
+
+v4 = v2 + result3
+return(v4)
+\end{Verbatim}

diff --git a/talk/icooolps2011/code/trace5.tex b/talk/icooolps2011/code/trace5.tex
new file mode 100644
--- /dev/null
+++ b/talk/icooolps2011/code/trace5.tex
@@ -0,0 +1,18 @@
+\begin{Verbatim}
+# inst.getattr("a")
+map1 = inst.map
+guard(map1 == 0xb74af4a8)
+storage1 = inst.storage
+result1 = storage1[0]
+
+# inst.getattr("b")
+cls1 = inst.cls
+guard(cls1 == 0xb7aaaaf8)
+version1 = cls1.version
+guard(version1 == 0xb7bbbb18)
+v2 = result1 + 41
+
+# inst.getattr("c")
+v4 = v2 + 17
+return(v4)
+\end{Verbatim}

diff --git a/talk/icooolps2011/code/interpreter-slow.tex b/talk/icooolps2011/code/interpreter-slow.tex
new file mode 100644
--- /dev/null
+++ b/talk/icooolps2011/code/interpreter-slow.tex
@@ -0,0 +1,39 @@
+\begin{Verbatim}[commandchars=\\\{\}]
+\PY{k}{class} \PY{n+nc}{Class}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:}
+    \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{name} \PY{o}{=} \PY{n}{name}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{methods} \PY{o}{=} \PY{p}{\PYZob{}}\PY{p}{\PYZcb{}}
+
+    \PY{k}{def} \PY{n+nf}{instantiate}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{)}\PY{p}{:}
+        \PY{k}{return} \PY{n}{Instance}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{)}
+
+    \PY{k}{def} \PY{n+nf}{find\PYZus{}method}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:}
+        \PY{n}{result} \PY{o}{=} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{methods}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{)}
+        \PY{k}{if} \PY{n}{result} \PY{o+ow}{is} \PY{o+ow}{not} \PY{n+nb+bp}{None}\PY{p}{:}
+            \PY{k}{return} \PY{n}{result}
+        \PY{k}{raise} \PY{n+ne}{AttributeError}\PY{p}{(}\PY{n}{name}\PY{p}{)}
+
+    \PY{k}{def} \PY{n+nf}{change\PYZus{}method}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{,} \PY{n}{value}\PY{p}{)}\PY{p}{:}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{methods}\PY{p}{[}\PY{n}{name}\PY{p}{]} \PY{o}{=} \PY{n}{value}
+
+
+\PY{k}{class} \PY{n+nc}{Instance}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:}
+    \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{cls}\PY{p}{)}\PY{p}{:}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{cls} \PY{o}{=} \PY{n}{cls}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{attributes} \PY{o}{=} \PY{p}{\PYZob{}}\PY{p}{\PYZcb{}}
+
+    \PY{k}{def} \PY{n+nf}{getfield}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:}
+        \PY{n}{result} \PY{o}{=} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{attributes}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{)}
+        \PY{k}{if} \PY{n}{result} \PY{o+ow}{is} \PY{o+ow}{not} \PY{n+nb+bp}{None}\PY{p}{:}
+            \PY{k}{return} \PY{n}{result}
+        \PY{k}{raise} \PY{n+ne}{AttributeError}\PY{p}{(}\PY{n}{name}\PY{p}{)}
+
+    \PY{k}{def} \PY{n+nf}{write\PYZus{}attribute}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{,} \PY{n}{value}\PY{p}{)}\PY{p}{:}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{attributes}\PY{p}{[}\PY{n}{name}\PY{p}{]} \PY{o}{=} \PY{n}{value}
+
+    \PY{k}{def} \PY{n+nf}{getattr}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:}
+        \PY{k}{try}\PY{p}{:}
+            \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{getfield}\PY{p}{(}\PY{n}{name}\PY{p}{)}
+        \PY{k}{except} \PY{n+ne}{AttributeError}\PY{p}{:}
+            \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{cls}\PY{o}{.}\PY{n}{find\PYZus{}method}\PY{p}{(}\PY{n}{name}\PY{p}{)}
+\end{Verbatim}

diff --git a/talk/icooolps2011/code/version.tex b/talk/icooolps2011/code/version.tex
new file mode 100644
--- /dev/null
+++ b/talk/icooolps2011/code/version.tex
@@ -0,0 +1,26 @@
+\begin{Verbatim}[commandchars=\\\{\}]
+\PY{k}{class} \PY{n+nc}{VersionTag}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:}
+    \PY{k}{pass}
+
+\PY{k}{class} \PY{n+nc}{Class}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:}
+    \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{name} \PY{o}{=} \PY{n}{name}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{methods} \PY{o}{=} \PY{p}{\PYZob{}}\PY{p}{\PYZcb{}}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{version} \PY{o}{=} \PY{n}{VersionTag}\PY{p}{(}\PY{p}{)}
+
+    \PY{k}{def} \PY{n+nf}{find\PYZus{}method}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:}
+        \PY{n+nb+bp}{self} \PY{o}{=} \PY{n}{hint}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{promote}\PY{o}{=}\PY{n+nb+bp}{True}\PY{p}{)}
+        \PY{n}{version} \PY{o}{=} \PY{n}{hint}\PY{p}{(}\PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{version}\PY{p}{,} \PY{n}{promote}\PY{o}{=}\PY{n+nb+bp}{True}\PY{p}{)}
+        \PY{n}{result} \PY{o}{=} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{\PYZus{}find\PYZus{}method}\PY{p}{(}\PY{n}{name}\PY{p}{,} \PY{n}{version}\PY{p}{)}
+        \PY{k}{if} \PY{n}{result} \PY{o+ow}{is} \PY{o+ow}{not} \PY{n+nb+bp}{None}\PY{p}{:}
+            \PY{k}{return} \PY{n}{result}
+        \PY{k}{raise} \PY{n+ne}{AttributeError}\PY{p}{(}\PY{n}{name}\PY{p}{)}
+
+    \PY{n+nd}{@purefunction}
+    \PY{k}{def} \PY{n+nf}{\PYZus{}find\PYZus{}method}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{,} \PY{n}{version}\PY{p}{)}\PY{p}{:}
+        \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{methods}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{)}
+
+    \PY{k}{def} \PY{n+nf}{change\PYZus{}method}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{,} \PY{n}{value}\PY{p}{)}\PY{p}{:}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{methods}\PY{p}{[}\PY{n}{name}\PY{p}{]} \PY{o}{=} \PY{n}{value}
+        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{version} \PY{o}{=} \PY{n}{VersionTag}\PY{p}{(}\PY{p}{)}
+\end{Verbatim}

diff --git a/talk/icooolps2011/code/trace3.tex b/talk/icooolps2011/code/trace3.tex
new file mode 100644
--- /dev/null
+++ b/talk/icooolps2011/code/trace3.tex
@@ -0,0 +1,23 @@
+\begin{Verbatim}
+# inst.getattr("a")
+map1 = inst.map
+guard(map1 == 0xb74af4a8)
+storage1 = inst.storage
+result1 = storage1[0]
+
+# inst.getattr("b")
+cls1 = inst.cls
+methods1 = cls1.methods
+result2 = dict.get(methods1, "b")
+guard(result2 is not None)
+v2 = result1 + result2
+
+# inst.getattr("c")
+cls2 = inst.cls
+methods2 = cls2.methods
+result3 = dict.get(methods2, "c")
+guard(result3 is not None)
+
+v4 = v2 + result3
+return(v4)
+\end{Verbatim}

diff --git a/talk/icooolps2011/Makefile b/talk/icooolps2011/Makefile
--- a/talk/icooolps2011/Makefile
+++ b/talk/icooolps2011/Makefile
@@ -1,5 +1,5 @@
 
-jit-hints.pdf: paper.tex paper.bib code/interpreter-slow.tex code/map.tex
+jit-hints.pdf: paper.tex paper.bib code/interpreter-slow.tex code/map.tex code/version.tex
 	pdflatex paper
 	bibtex paper
 	pdflatex paper

diff --git a/talk/icooolps2011/paper.tex b/talk/icooolps2011/paper.tex
--- a/talk/icooolps2011/paper.tex
+++ b/talk/icooolps2011/paper.tex
@@ -89,6 +89,10 @@
 %___________________________________________________________________________
 \section{Introduction}
 
+XXX how exactly
+the hints work that interpreter authors can use to improve the execution speed
+of the programs running on their interpreters?
+
 
 %___________________________________________________________________________
 \section{The PyPy Project}
@@ -107,10 +111,6 @@
 %___________________________________________________________________________
 \section{Controlling The Extent of Tracing}
 
-XXX how exactly
-the hints work that interpreter authors can use to improve the execution speed
-of the programs running on their interpreters?
-
 
 \subsection{Background}
 
@@ -133,15 +133,14 @@
 the loop in the user function that is being considered. At this point, it can
 have traced many iterations of the interpreter main loop.
 
-Here's a diagram of this process:
-
 \begin{figure*}
 \includegraphics[scale=0.5]{figures/trace-levels}
 \caption{The levels involved in tracing}
 \label{fig:trace-levels}
 \end{figure*}
 
-On the left you see the levels of execution. The CPU executes the binary of
+Figure~\ref{fig:trace-levels} shows a diagram of the process. On the left you
+see the levels of execution. The CPU executes the binary of
 PyPy's Python interpreter, which consists of RPython functions that have been
 compiled first to C, then to machine code. Some of these functions contain
 loops, others don't. The interpreter runs a Python program written by a
@@ -658,19 +657,19 @@
 find a way to get rid of these dictionary lookups somehow.
 
 Let's assume we trace through code that sums three attributes, such as:
-\begin{Verbatim}[commandchars=\\\{\}]
-\PY{n}{inst}\PY{o}{.}\PY{n}{getattr}\PY{p}{(}\PY{l+s}{"}\PY{l+s}{a}\PY{l+s}{"}\PY{p}{)} \PY{o}{+} \PY{n}{inst}\PY{o}{.}\PY{n}{getattr}\PY{p}{(}\PY{l+s}{"}\PY{l+s}{b}\PY{l+s}{"}\PY{p}{)} \PY{o}{+} \PY{n}{inst}\PY{o}{.}\PY{n}{getattr}\PY{p}{(}\PY{l+s}{"}\PY{l+s}{c}\PY{l+s}{"}\PY{p}{)}
+
+\begin{Verbatim}
+inst.getattr("a") + inst.getattr("b") + inst.getattr("c")
 \end{Verbatim}
 
-The trace could look like this:
-
 \begin{figure}
 \input{code/trace1.tex}
 \caption{Trace Through the Object Model}
 \label{fig:trace1}
 \end{figure}
 
-In this example, the attribute \texttt{a} is found on the instance, but the
+The trace would look like in Figure~\ref{fig:trace1}. In this example, the
+attribute \texttt{a} is found on the instance, but the
 attributes \texttt{b} and \texttt{c} are found on the class. The trace indeed contains
 five calls to \texttt{dict.get}, which is slow.
 
@@ -717,69 +716,25 @@
 
 With this changed instance implementation, the trace we had above changes to the
 following, where \texttt{0xb74af4a8} is the memory address of the Map instance that
-has been promoted:
-\begin{Verbatim}[commandchars=\\\{\}]
-\PY{c}{# inst.getattr("a")}
-\PY{n}{map1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{map}
-\PY{n}{guard}\PY{p}{(}\PY{n}{map1} \PY{o}{==} \PY{l+m+mh}{0xb74af4a8}\PY{p}{)}
-\PY{n}{index1} \PY{o}{=} \PY{n}{Map}\PY{o}{.}\PY{n}{getindex}\PY{p}{(}\PY{n}{map1}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{a}\PY{l+s}{"}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{index1} \PY{o}{!=} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)}
-\PY{n}{storage1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{storage}
-\PY{n}{result1} \PY{o}{=} \PY{n}{storage1}\PY{p}{[}\PY{n}{index1}\PY{p}{]}
+has been promoted, see Figure~\ref{fig:trace2}.
 
-\PY{c}{# inst.getattr("b")}
-\PY{n}{map2} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{map}
-\PY{n}{guard}\PY{p}{(}\PY{n}{map2} \PY{o}{==} \PY{l+m+mh}{0xb74af4a8}\PY{p}{)}
-\PY{n}{index2} \PY{o}{=} \PY{n}{Map}\PY{o}{.}\PY{n}{getindex}\PY{p}{(}\PY{n}{map2}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{b}\PY{l+s}{"}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{index2} \PY{o}{==} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)}
-\PY{n}{cls1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{cls}
-\PY{n}{methods1} \PY{o}{=} \PY{n}{cls}\PY{o}{.}\PY{n}{methods}
-\PY{n}{result2} \PY{o}{=} \PY{n+nb}{dict}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{methods1}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{b}\PY{l+s}{"}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{result2} \PY{o+ow}{is} \PY{o+ow}{not} \PY{n+nb+bp}{None}\PY{p}{)}
-\PY{n}{v2} \PY{o}{=} \PY{n}{result1} \PY{o}{+} \PY{n}{result2}
-
-\PY{c}{# inst.getattr("c")}
-\PY{n}{map3} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{map}
-\PY{n}{guard}\PY{p}{(}\PY{n}{map3} \PY{o}{==} \PY{l+m+mh}{0xb74af4a8}\PY{p}{)}
-\PY{n}{index3} \PY{o}{=} \PY{n}{Map}\PY{o}{.}\PY{n}{getindex}\PY{p}{(}\PY{n}{map3}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{c}\PY{l+s}{"}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{index3} \PY{o}{==} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)}
-\PY{n}{cls1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{cls}
-\PY{n}{methods2} \PY{o}{=} \PY{n}{cls}\PY{o}{.}\PY{n}{methods}
-\PY{n}{result3} \PY{o}{=} \PY{n+nb}{dict}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{methods2}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{c}\PY{l+s}{"}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{result3} \PY{o+ow}{is} \PY{o+ow}{not} \PY{n+nb+bp}{None}\PY{p}{)}
-
-\PY{n}{v4} \PY{o}{=} \PY{n}{v2} \PY{o}{+} \PY{n}{result3}
-\PY{k}{return}\PY{p}{(}\PY{n}{v4}\PY{p}{)}
-\end{Verbatim}
+\begin{figure}
+\input{code/trace2.tex}
+\caption{Unoptimized Trace After the Introduction of Maps}
+\label{fig:trace2}
+\end{figure}
 
 The calls to \texttt{Map.getindex} can be optimized away, because they are calls to
 a pure function and they have constant arguments. That means that \texttt{index1/2/3}
 are constant and the guards on them can be removed. All but the first guard on
 the map will be optimized away too, because the map cannot have changed in
-between. The optimized trace looks like this:
-\begin{Verbatim}[commandchars=\\\{\}]
-\PY{c}{# inst.getattr("a")}
-\PY{n}{map1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{map}
-\PY{n}{guard}\PY{p}{(}\PY{n}{map1} \PY{o}{==} \PY{l+m+mh}{0xb74af4a8}\PY{p}{)}
-\PY{n}{storage1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{storage}
-\PY{n}{result1} \PY{o}{=} \PY{n}{storage1}\PY{p}{[}\PY{l+m+mi}{0}\PY{p}{]}
+between. The optimized trace looks can be seen in Figure~\ref{fig:trace3}
 
-\PY{c}{# inst.getattr("b")}
-\PY{n}{cls1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{cls}
-\PY{n}{methods1} \PY{o}{=} \PY{n}{cls1}\PY{o}{.}\PY{n}{methods}
-\PY{n}{result2} \PY{o}{=} \PY{n+nb}{dict}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{methods1}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{b}\PY{l+s}{"}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{result2} \PY{o+ow}{is} \PY{o+ow}{not} \PY{n+nb+bp}{None}\PY{p}{)}
-\PY{n}{v2} \PY{o}{=} \PY{n}{result1} \PY{o}{+} \PY{n}{result2}
-
-\PY{c}{# inst.getattr("c")}
-\PY{n}{cls2} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{cls}
-\PY{n}{methods2} \PY{o}{=} \PY{n}{cls2}\PY{o}{.}\PY{n}{methods}
-\PY{n}{result3} \PY{o}{=} \PY{n+nb}{dict}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{methods2}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{c}\PY{l+s}{"}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{result3} \PY{o+ow}{is} \PY{o+ow}{not} \PY{n+nb+bp}{None}\PY{p}{)}
-
-\PY{n}{v4} \PY{o}{=} \PY{n}{v2} \PY{o}{+} \PY{n}{result3}
-\PY{k}{return}\PY{p}{(}\PY{n}{v4}\PY{p}{)}
-\end{Verbatim}
+\begin{figure}
+\input{code/trace3.tex}
+\caption{Optimized Trace After the Introduction of Maps}
+\label{fig:trace3}
+\end{figure}
 
 The index \texttt{0} that is used to read out of the \texttt{storage} array is the result
 of the constant-folded \texttt{getindex} call. This trace is already much better than
@@ -807,99 +762,36 @@
 version)} pair will always be the same, i.e. it is a pure operation.  To help
 the JIT to detect this case, we factor it out in a helper method which is
 explicitly marked as \texttt{@purefunction}. The refactored \texttt{Class} looks like
-this:
-\begin{Verbatim}[commandchars=\\\{\}]
-\PY{k}{class} \PY{n+nc}{VersionTag}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:}
-    \PY{k}{pass}
+in Figure~\ref{fig:version}
 
-\PY{k}{class} \PY{n+nc}{Class}\PY{p}{(}\PY{n+nb}{object}\PY{p}{)}\PY{p}{:}
-    \PY{k}{def} \PY{n+nf}{\PYZus{}\PYZus{}init\PYZus{}\PYZus{}}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:}
-        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{name} \PY{o}{=} \PY{n}{name}
-        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{methods} \PY{o}{=} \PY{p}{\PYZob{}}\PY{p}{\PYZcb{}}
-        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{version} \PY{o}{=} \PY{n}{VersionTag}\PY{p}{(}\PY{p}{)}
-
-    \PY{k}{def} \PY{n+nf}{find\PYZus{}method}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{)}\PY{p}{:}
-        \PY{n+nb+bp}{self} \PY{o}{=} \PY{n}{hint}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{promote}\PY{o}{=}\PY{n+nb+bp}{True}\PY{p}{)}
-        \PY{n}{version} \PY{o}{=} \PY{n}{hint}\PY{p}{(}\PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{version}\PY{p}{,} \PY{n}{promote}\PY{o}{=}\PY{n+nb+bp}{True}\PY{p}{)}
-        \PY{n}{result} \PY{o}{=} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{\PYZus{}find\PYZus{}method}\PY{p}{(}\PY{n}{name}\PY{p}{,} \PY{n}{version}\PY{p}{)}
-        \PY{k}{if} \PY{n}{result} \PY{o+ow}{is} \PY{o+ow}{not} \PY{n+nb+bp}{None}\PY{p}{:}
-            \PY{k}{return} \PY{n}{result}
-        \PY{k}{raise} \PY{n+ne}{AttributeError}\PY{p}{(}\PY{n}{name}\PY{p}{)}
-
-    \PY{n+nd}{@purefunction}
-    \PY{k}{def} \PY{n+nf}{\PYZus{}find\PYZus{}method}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{,} \PY{n}{version}\PY{p}{)}\PY{p}{:}
-        \PY{k}{return} \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{methods}\PY{o}{.}\PY{n}{get}\PY{p}{(}\PY{n}{name}\PY{p}{)}
-
-    \PY{k}{def} \PY{n+nf}{change\PYZus{}method}\PY{p}{(}\PY{n+nb+bp}{self}\PY{p}{,} \PY{n}{name}\PY{p}{,} \PY{n}{value}\PY{p}{)}\PY{p}{:}
-        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{methods}\PY{p}{[}\PY{n}{name}\PY{p}{]} \PY{o}{=} \PY{n}{value}
-        \PY{n+nb+bp}{self}\PY{o}{.}\PY{n}{version} \PY{o}{=} \PY{n}{VersionTag}\PY{p}{(}\PY{p}{)}
-\end{Verbatim}
+\begin{figure}
+\input{code/version.tex}
+\caption{Versioning of Classes}
+\label{fig:version}
+\end{figure}
 
 What is interesting here is that \texttt{\_find\_method} takes the \texttt{version}
 argument but it does not use it at all. Its only purpose is to make the call
 pure (because when the version number changes, the result of the call might be
 different than the previous one).
 
-The trace with this new class implementation looks like this:
-\begin{Verbatim}[commandchars=\\\{\}]
-\PY{c}{# inst.getattr("a")}
-\PY{n}{map1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{map}
-\PY{n}{guard}\PY{p}{(}\PY{n}{map1} \PY{o}{==} \PY{l+m+mh}{0xb74af4a8}\PY{p}{)}
-\PY{n}{index1} \PY{o}{=} \PY{n}{Map}\PY{o}{.}\PY{n}{getindex}\PY{p}{(}\PY{n}{map1}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{a}\PY{l+s}{"}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{index1} \PY{o}{!=} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)}
-\PY{n}{storage1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{storage}
-\PY{n}{result1} \PY{o}{=} \PY{n}{storage1}\PY{p}{[}\PY{n}{index1}\PY{p}{]}
+\begin{figure}
+\input{code/trace4.tex}
+\caption{Unoptimized Trace After Introduction of Versioned Classes}
+\label{fig:trace4}
+\end{figure}
 
-\PY{c}{# inst.getattr("b")}
-\PY{n}{map2} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{map}
-\PY{n}{guard}\PY{p}{(}\PY{n}{map2} \PY{o}{==} \PY{l+m+mh}{0xb74af4a8}\PY{p}{)}
-\PY{n}{index2} \PY{o}{=} \PY{n}{Map}\PY{o}{.}\PY{n}{getindex}\PY{p}{(}\PY{n}{map2}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{b}\PY{l+s}{"}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{index2} \PY{o}{==} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)}
-\PY{n}{cls1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{cls}
-\PY{n}{guard}\PY{p}{(}\PY{n}{cls1} \PY{o}{==} \PY{l+m+mh}{0xb7aaaaf8}\PY{p}{)}
-\PY{n}{version1} \PY{o}{=} \PY{n}{cls1}\PY{o}{.}\PY{n}{version}
-\PY{n}{guard}\PY{p}{(}\PY{n}{version1} \PY{o}{==} \PY{l+m+mh}{0xb7bbbb18}\PY{p}{)}
-\PY{n}{result2} \PY{o}{=} \PY{n}{Class}\PY{o}{.}\PY{n}{\PYZus{}find\PYZus{}method}\PY{p}{(}\PY{n}{cls}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{b}\PY{l+s}{"}\PY{p}{,} \PY{n}{version1}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{result2} \PY{o+ow}{is} \PY{o+ow}{not} \PY{n+nb+bp}{None}\PY{p}{)}
-\PY{n}{v2} \PY{o}{=} \PY{n}{result1} \PY{o}{+} \PY{n}{result2}
-
-\PY{c}{# inst.getattr("c")}
-\PY{n}{map3} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{map}
-\PY{n}{guard}\PY{p}{(}\PY{n}{map3} \PY{o}{==} \PY{l+m+mh}{0xb74af4a8}\PY{p}{)}
-\PY{n}{index3} \PY{o}{=} \PY{n}{Map}\PY{o}{.}\PY{n}{getindex}\PY{p}{(}\PY{n}{map3}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{c}\PY{l+s}{"}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{index3} \PY{o}{==} \PY{o}{-}\PY{l+m+mi}{1}\PY{p}{)}
-\PY{n}{cls2} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{cls}
-\PY{n}{guard}\PY{p}{(}\PY{n}{cls2} \PY{o}{==} \PY{l+m+mh}{0xb7aaaaf8}\PY{p}{)}
-\PY{n}{version2} \PY{o}{=} \PY{n}{cls2}\PY{o}{.}\PY{n}{version}
-\PY{n}{guard}\PY{p}{(}\PY{n}{version2} \PY{o}{==} \PY{l+m+mh}{0xb7bbbb18}\PY{p}{)}
-\PY{n}{result3} \PY{o}{=} \PY{n}{Class}\PY{o}{.}\PY{n}{\PYZus{}find\PYZus{}method}\PY{p}{(}\PY{n}{cls}\PY{p}{,} \PY{l+s}{"}\PY{l+s}{c}\PY{l+s}{"}\PY{p}{,} \PY{n}{version2}\PY{p}{)}
-\PY{n}{guard}\PY{p}{(}\PY{n}{result3} \PY{o+ow}{is} \PY{o+ow}{not} \PY{n+nb+bp}{None}\PY{p}{)}
-
-\PY{n}{v4} \PY{o}{=} \PY{n}{v2} \PY{o}{+} \PY{n}{result3}
-\PY{k}{return}\PY{p}{(}\PY{n}{v4}\PY{p}{)}
-\end{Verbatim}
-
+The trace with this new class implementation can be seen in
+Figure~\ref{fig:trace4}.
 The calls to \texttt{Class.\_find\_method} can now be optimized away, also the
 promotion of the class and the version, except for the first one. The final
-optimized trace looks like this:
-\begin{Verbatim}[commandchars=\\\{\}]
-\PY{c}{# inst.getattr("a")}
-\PY{n}{map1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{map}
-\PY{n}{guard}\PY{p}{(}\PY{n}{map1} \PY{o}{==} \PY{l+m+mh}{0xb74af4a8}\PY{p}{)}
-\PY{n}{storage1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{storage}
-\PY{n}{result1} \PY{o}{=} \PY{n}{storage1}\PY{p}{[}\PY{l+m+mi}{0}\PY{p}{]}
+optimized trace can be seen in Figure~\ref{fig:trace5}.
 
-\PY{c}{# inst.getattr("b")}
-\PY{n}{cls1} \PY{o}{=} \PY{n}{inst}\PY{o}{.}\PY{n}{cls}
-\PY{n}{guard}\PY{p}{(}\PY{n}{cls1} \PY{o}{==} \PY{l+m+mh}{0xb7aaaaf8}\PY{p}{)}
-\PY{n}{version1} \PY{o}{=} \PY{n}{cls1}\PY{o}{.}\PY{n}{version}
-\PY{n}{guard}\PY{p}{(}\PY{n}{version1} \PY{o}{==} \PY{l+m+mh}{0xb7bbbb18}\PY{p}{)}
-\PY{n}{v2} \PY{o}{=} \PY{n}{result1} \PY{o}{+} \PY{l+m+mi}{41}
-
-\PY{c}{# inst.getattr("c")}
-\PY{n}{v4} \PY{o}{=} \PY{n}{v2} \PY{o}{+} \PY{l+m+mi}{17}
-\PY{k}{return}\PY{p}{(}\PY{n}{v4}\PY{p}{)}
-\end{Verbatim}
+\begin{figure}
+\input{code/trace5.tex}
+\caption{Optimized Trace After Introduction of Versioned Classes}
+\label{fig:trace5}
+\end{figure}
 
 The constants \texttt{41} and \texttt{17} are the results of the folding of the
 \texttt{\_find\_method`} calls. This final trace is now very good. It no longer performs any

diff --git a/talk/icooolps2011/code/trace4.tex b/talk/icooolps2011/code/trace4.tex
new file mode 100644
--- /dev/null
+++ b/talk/icooolps2011/code/trace4.tex
@@ -0,0 +1,37 @@
+\begin{Verbatim}
+# inst.getattr("a")
+map1 = inst.map
+guard(map1 == 0xb74af4a8)
+index1 = Map.getindex(map1, "a")
+guard(index1 != -1)
+storage1 = inst.storage
+result1 = storage1[index1]
+
+# inst.getattr("b")
+map2 = inst.map
+guard(map2 == 0xb74af4a8)
+index2 = Map.getindex(map2, "b")
+guard(index2 == -1)
+cls1 = inst.cls
+guard(cls1 == 0xb7aaaaf8)
+version1 = cls1.version
+guard(version1 == 0xb7bbbb18)
+result2 = Class._find_method(cls, "b", version1)
+guard(result2 is not None)
+v2 = result1 + result2
+
+# inst.getattr("c")
+map3 = inst.map
+guard(map3 == 0xb74af4a8)
+index3 = Map.getindex(map3, "c")
+guard(index3 == -1)
+cls2 = inst.cls
+guard(cls2 == 0xb7aaaaf8)
+version2 = cls2.version
+guard(version2 == 0xb7bbbb18)
+result3 = Class._find_method(cls, "c", version2)
+guard(result3 is not None)
+
+v4 = v2 + result3
+return(v4)
+\end{Verbatim}

diff --git a/talk/icooolps2011/code/version.py b/talk/icooolps2011/code/version.py
new file mode 100644
--- /dev/null
+++ b/talk/icooolps2011/code/version.py
@@ -0,0 +1,24 @@
+class VersionTag(object):
+    pass
+
+class Class(object):
+    def __init__(self, name):
+        self.name = name
+        self.methods = {}
+        self.version = VersionTag()
+
+    def find_method(self, name):
+        self = hint(self, promote=True)
+        version = hint(self.version, promote=True)
+        result = self._find_method(name, version)
+        if result is not None:
+            return result
+        raise AttributeError(name)
+
+    @purefunction
+    def _find_method(self, name, version):
+        return self.methods.get(name)
+
+    def change_method(self, name, value):
+        self.methods[name] = value
+        self.version = VersionTag()


More information about the Pypy-commit mailing list