Added benchmark data for privileged members under v8 (currently Figure 1)
parent
a670dbf2e0
commit
63083533dc
|
@ -7,6 +7,7 @@
|
||||||
\usepackage{color}
|
\usepackage{color}
|
||||||
\usepackage{hyperref}
|
\usepackage{hyperref}
|
||||||
\usepackage{cite}
|
\usepackage{cite}
|
||||||
|
\usepackage{multirow}
|
||||||
|
|
||||||
\hypersetup{colorlinks,
|
\hypersetup{colorlinks,
|
||||||
citecolor=black,
|
citecolor=black,
|
||||||
|
@ -21,6 +22,7 @@
|
||||||
\definecolor{lightgray}{rgb}{0.6,0.6,0.6}
|
\definecolor{lightgray}{rgb}{0.6,0.6,0.6}
|
||||||
|
|
||||||
\newcommand{\jsref}{\textmd Listing~\ref}
|
\newcommand{\jsref}{\textmd Listing~\ref}
|
||||||
|
\newcommand{\fref}{\textmd Figure~\ref}
|
||||||
|
|
||||||
\lstdefinelanguage{JavaScript}{%
|
\lstdefinelanguage{JavaScript}{%
|
||||||
keywords={%
|
keywords={%
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
function Foo( name )
|
||||||
|
{
|
||||||
|
this.getName = function()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setName = function( newname )
|
||||||
|
{
|
||||||
|
name = newname;
|
||||||
|
};
|
||||||
|
}
|
|
@ -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 ];
|
||||||
|
}
|
|
@ -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' )
|
||||||
|
);
|
|
@ -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' )
|
||||||
|
);
|
|
@ -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
|
an argument) within the constructor that is only accessible to the
|
||||||
\dfn{privileged member} \func{getName()}.
|
\dfn{privileged member} \func{getName()}.
|
||||||
|
|
||||||
\begin{lstlisting}[%
|
\lstinputlisting[%
|
||||||
label=lst:privileged,
|
label=lst:privileged,
|
||||||
caption=Using privileged members to encapsulate data
|
caption=Using privileged members to encapsulate data
|
||||||
]
|
]{lst/privileged-members.js}
|
||||||
function Foo( name )
|
|
||||||
{
|
|
||||||
this.getName = function()
|
|
||||||
{
|
|
||||||
return name;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.setName = function( newname )
|
|
||||||
{
|
|
||||||
name = newname;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
\end{lstlisting}
|
|
||||||
|
|
||||||
If \var{name} in \jsref{lst:privileged} is encapsulated within the constructor,
|
If \var{name} in \jsref{lst:privileged} is encapsulated within the constructor,
|
||||||
our methods that \emph{access} that encapsulated data must \emph{too} be
|
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
|
members.} otherwise, if placed within the prototype, \var{name} would be out of
|
||||||
scope. This implementation has an unfortunate consequence --- our methods are
|
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
|
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
|
created, which has obvious performance penalties (see
|
||||||
of thumb, one should only use privileged members for methods that access
|
\fref{fig:proto-priv-cmp}).\footnote{As a general rule of thumb, one should only
|
||||||
encapsulated data; all other members should be part of the prototype.}
|
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
|
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
|
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
|
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
|
of privileged members is Dojo at http://dojotoolkit.org.} This serves as a clear
|
||||||
|
|
Loading…
Reference in New Issue