[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