From 63083533dc056ac2d306482af202b5b64001cccc Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Wed, 22 Feb 2012 20:18:15 -0500 Subject: [PATCH] Added benchmark data for privileged members under v8 (currently Figure 1) --- coope.sty | 2 ++ lst/privileged-members.js | 12 ++++++++ perf/inst-call-cmp.js | 34 ++++++++++++++++++++++ perf/privileged-inst-memory.js | 21 ++++++++++++++ perf/proto-inst-memory.js | 25 ++++++++++++++++ sec/class-like.tex | 52 +++++++++++++++++++++------------- 6 files changed, 127 insertions(+), 19 deletions(-) create mode 100644 lst/privileged-members.js create mode 100644 perf/inst-call-cmp.js create mode 100644 perf/privileged-inst-memory.js create mode 100644 perf/proto-inst-memory.js diff --git a/coope.sty b/coope.sty index 5ba1eab..8367db0 100644 --- a/coope.sty +++ b/coope.sty @@ -7,6 +7,7 @@ \usepackage{color} \usepackage{hyperref} \usepackage{cite} +\usepackage{multirow} \hypersetup{colorlinks, citecolor=black, @@ -21,6 +22,7 @@ \definecolor{lightgray}{rgb}{0.6,0.6,0.6} \newcommand{\jsref}{\textmd Listing~\ref} +\newcommand{\fref}{\textmd Figure~\ref} \lstdefinelanguage{JavaScript}{% keywords={% diff --git a/lst/privileged-members.js b/lst/privileged-members.js new file mode 100644 index 0000000..ad9562c --- /dev/null +++ b/lst/privileged-members.js @@ -0,0 +1,12 @@ +function Foo( name ) +{ + this.getName = function() + { + return name; + }; + + this.setName = function( newname ) + { + name = newname; + }; +} diff --git a/perf/inst-call-cmp.js b/perf/inst-call-cmp.js new file mode 100644 index 0000000..555f993 --- /dev/null +++ b/perf/inst-call-cmp.js @@ -0,0 +1,34 @@ +/** + * Performance testing on an instance of Foo (rather specific, I know. + * Lazy-programmer-who-wants-to-get-back-to-writing-his-article syndrome). + */ + +exports.run = function( Foo ) +{ + // get initial memory usage and start time in ms + var mem = process.memoryUsage().heapUsed, + start = ( new Date() ).getTime(); + + // instantiate a number of Foo's, keeping them in memory. + var i = count = 1e6, a = []; + while ( i-- ) + { + a[i] = new Foo(); + } + + // gather final statistics before doing any additional work + var end = ( ( new Date() ).getTime() - start ), + mem_end = ( process.memoryUsage().heapUsed - mem ), + cstart = ( new Date() ).getTime(); + + i = count; + while ( i-- ) + { + a[0].getName(); + a[0].setName(); + }; + + var cend = ( ( new Date() ).getTime() - cstart ); + + return [ mem_end, end, cend ]; +} diff --git a/perf/privileged-inst-memory.js b/perf/privileged-inst-memory.js new file mode 100644 index 0000000..3015cef --- /dev/null +++ b/perf/privileged-inst-memory.js @@ -0,0 +1,21 @@ +/** + * Outputs the amount of time to run various tests against a protected member + * implementation of Foo + */ + +function Foo( name ) +{ + this.getName = function() + { + return name; + }; + + this.setName = function( newname ) + { + name = newname; + }; +} + +console.log( + require( './inst-call-cmp' ).run( Foo ).join( '\t' ) +); diff --git a/perf/proto-inst-memory.js b/perf/proto-inst-memory.js new file mode 100644 index 0000000..662c178 --- /dev/null +++ b/perf/proto-inst-memory.js @@ -0,0 +1,25 @@ +/** + * Outputs the amount of time to run various tests against a prototype + * implementation of Foo + */ + +function Foo( name ) +{ + this.name = name; +} + +Foo.prototype = { + getName: function() + { + return this.name; + }, + + setName: function( newname ) + { + this.name = newname; + }, +}; + +console.log( + require( './inst-call-cmp' ).run( Foo ).join( '\t' ) +); diff --git a/sec/class-like.tex b/sec/class-like.tex index efeec7b..ac9ab20 100644 --- a/sec/class-like.tex +++ b/sec/class-like.tex @@ -216,23 +216,10 @@ that functions introduce scope, allowing us to define a local variable (or use an argument) within the constructor that is only accessible to the \dfn{privileged member} \func{getName()}. -\begin{lstlisting}[% +\lstinputlisting[% label=lst:privileged, caption=Using privileged members to encapsulate data -] -function Foo( name ) -{ - this.getName = function() - { - return name; - }; - - this.setName = function( newname ) - { - name = newname; - }; -} -\end{lstlisting} +]{lst/privileged-members.js} If \var{name} in \jsref{lst:privileged} is encapsulated within the constructor, our methods that \emph{access} that encapsulated data must \emph{too} be @@ -240,12 +227,39 @@ declared within the constructor;\footnote{One may mix prototypes and privileged members.} otherwise, if placed within the prototype, \var{name} would be out of scope. This implementation has an unfortunate consequence --- our methods are now being \emph{redeclared} each and every time a new instance of \var{Foo} is -created, which has obvious performance penalties.\footnote{As a general rule -of thumb, one should only use privileged members for methods that access -encapsulated data; all other members should be part of the prototype.} +created, which has obvious performance penalties (see +\fref{fig:proto-priv-cmp}).\footnote{As a general rule of thumb, one should only +use privileged members for methods that access encapsulated data; all other +members should be part of the prototype.} + +\begin{figure} + \center + \begin{tabular}{r|r|r|r|} + \cline{2-4} + & Heap Usage + & \multicolumn{1}{|c|}{Inst. Time} + & \multicolumn{1}{|c|}{Call Time} \\ + \hline + \multicolumn{1}{|r|}{\jsref{lst:proto-proper}} + & 49.7M & 234ms & 17ms \\ + \multicolumn{1}{|r|}{\jsref{lst:privileged}} + & 236.0M & 1134ms & 28ms \\ + \hline + \multicolumn{1}{|r|}{\% Change} & 374.8\% & 384.6\% & 64.7\% \\ + \hline + \end{tabular} +\caption{Comparing performance of privileged member and prototype +implementations under v8. The heap usage column represents the +heap usage after instantiating \var{Foo} under the respective implementation $n$ +times, and the Inst. CPU column reflects the amount of time spent instantiating +the $n$ objects. The Call CPU column reflects the amount of time spent invoking +\emph{each} member of \emph{one} instance $n$ times. $n = 1,000,000$. Lower +numbers are better. Different environments may have different results.} +\label{fig:proto-priv-cmp} +\end{figure} Due to these performance concerns, it is often undesirable to use privileged -members; many developers will instead simply prefix with an underscore members +members; many developers will instead prefix, with an underscore, members intended to be private (e.g. \code{this.\_name}) while keeping all methods on the prototype.\footnote{One example of a library that uses underscores in place of privileged members is Dojo at http://dojotoolkit.org.} This serves as a clear