1 <!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Transitional//EN"
2 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4 <!-- Copyright 2008 Google Inc. All rights reserved. -->
6 <title> Mandelbrot: JavaScript versus Native Client
</title>
7 <style type=
"text/css">
8 canvas
{ border:solid
}
10 <script type='application/x-javascript'
>
14 // A utility function to get the integer value of a user input field.
15 var getValue = function(id) {
16 var element = document.getElementById(id);
17 var value = element.value;
18 return parseInt(value);
21 // Compute the color for one pixel.
22 var mandelJavaScript = function(i, j, canvas_width) {
23 var cx = (4.0 / canvas_width) * i - 3.0;
24 var cy = 1.5 - (3.0 / canvas_width) * j;
28 var threshold = 1.0e8;
29 while (count < 256 && re * re + im * im < threshold) {
30 var new_re = re * re - im * im + cx;
31 var new_im = 2 * re * im + cy;
43 } else if (count < 16) {
47 } else if (count < 32) {
51 } else if (count < 64) {
55 } else if (count < 128) {
59 } else if (count < 256) {
71 // Compute the JavaScript mandelbrot picture and render into canvas.
72 var drawJavaScript = function(canvas_width, tile_width, context) {
75 for (var i = 0; i < canvas_width; ++i) {
76 for (var j = 0; j < canvas_width; ++j) {
77 var before_call = new Date();
78 var arr = mandelJavaScript(i, j, canvas_width);
79 var after_call = new Date();
80 var difftime = after_call.getTime() - before_call.getTime();
81 call_time += difftime;
82 before_call = new Date();
83 context.fillStyle = 'rgb(' + arr[0] + ',' + arr[1] + ',' + arr[2] + ')';
84 context.fillRect(i, j, 1, 1);
85 after_call = new Date();
86 difftime = after_call.getTime() - before_call.getTime();
87 canvas_time += difftime;
90 return [call_time, canvas_time];
93 // Compute and display the entire JavaScript mandelbrot picture, including
94 // printing the gathered timings.
95 var testJavaScript = function() {
96 // Set up the element where the time will be reported.
97 var time_element = document.getElementById('js_time');
98 time_element.innerHTML = '<b> JavaScript';
99 // Get the test parameters.
100 var canvas_width = getValue('canvas_width');
101 var tile_width = getValue('tile_width');
102 // Set up the canvas object and clear it.
103 var canvas = document.getElementById('js_canvas');
104 canvas.width = canvas_width;
105 canvas.height = canvas_width;
106 var context = canvas.getContext('2d');
107 context.fillStyle = 'rgb(0,0,0)';
108 context.fillRect(0, 0, canvas_width, canvas_width);
110 var test_time = drawJavaScript(canvas_width, tile_width, context);
111 // Update the time element with compute and canvas manipulation times.
112 time_element.innerHTML = '<b> JavaScript <br>' +
113 'compute time: ' + test_time[0] + ' milliseconds<br>' +
114 'canvas time: ' + test_time[1] + ' milliseconds<br>';
117 // The Native Client version uses a shared memory object to return
118 // the computed rgb values for the canvas points. As the number of
119 // points may vary as a user configuration, the size of the shared
120 // memory object may vary.
121 var getSharedMemorySize = function(canvas_width) {
122 // The picture we are computing is a square. Each element in the region
123 // is a string like 'rgb(rrr,ggg,bbb)', or 16 bytes.
124 var min_size = canvas_width * canvas_width * 16;
125 // The minimum allocation size for Native Client shared memory regions is 64K.
127 // For convenience, we find the next power of two that holds the size.
128 for (; bytes < min_size; bytes *= 2);
132 // Compute the Native Client mandelbrot picture and render into canvas.
133 var drawNativeClient = function(canvas_width,
137 // shm_size needs to be enough to keep 16 bytes per point.
138 var shm_size = getSharedMemorySize(canvas_width);
139 var shm = plugin.__shmFactory(shm_size);
140 var tiles_per_row = canvas_width / tile_width;
144 for (var x = 0; x < canvas_width; x += tile_width) {
145 for (var y = 0; y < canvas_width; y += tile_width) {
146 var before_call = new Date();
147 plugin.tiled(x, y, tile_width, tiles_per_row);
148 var str = shm.read(0, tile_width * tile_width * 16);
149 var after_call = new Date();
150 var difftime = after_call.getTime() - before_call.getTime();
151 call_time += difftime;
153 before_call = new Date();
154 for (var i = x; i < x + tile_width; ++i) {
155 for (var j = y; j < y + tile_width; ++j) {
156 context.fillStyle = str.substring(shmpos, shmpos + 16);
158 context.fillRect(i, j, 1, 1);
161 after_call = new Date();
162 difftime = after_call.getTime() - before_call.getTime();
163 canvas_time += difftime;
167 return [call_time, canvas_time];
170 // Compute and display the entire Native Client mandelbrot picture, including
171 // printing the gathered timings.
172 var testNativeClient = function() {
173 // Set up the element where the time will be reported.
174 var time_element = document.getElementById('nacl_time');
175 time_element.innerHTML = '<b>Native Client';
176 // Get the test parameters.
177 var canvas_width = getValue('canvas_width');
178 var tile_width = getValue('tile_width');
179 var tiles_per_row = canvas_width / tile_width;
180 // Set up the canvas object and clear it.
181 var canvas = document.getElementById('nacl_canvas');
182 canvas.width = canvas_width;
183 canvas.height = canvas_width;
184 var context = canvas.getContext('2d');
185 context.fillStyle = 'rgb(0,0,0)';
186 context.fillRect(0, 0, canvas_width, canvas_width);
187 // Get the Native Client plugin element.
188 var plugin = document.getElementById('nacl');
190 var test_time = drawNativeClient(canvas_width,
194 // Update the time element with compute and canvas manipulation times.
195 time_element.innerHTML = '<b>Native Client<br>(' +
196 tiles_per_row * tiles_per_row + ' square tiles ' +
197 tile_width + ' pixels wide)<br>' +
198 'compute time: ' + test_time[0] + ' milliseconds<br>' +
199 'canvas time: ' + test_time[1] + ' milliseconds<br>';
202 // Before running tests we need to ensure the Native Client module is loaded.
205 var RunTestsAfterLoad = function() {
206 if (plugin.__moduleReady) {
207 clearTimeout(startupTimeout);
208 // Do the tests one time by default.
212 if (plugin.__moduleReady == undefined) {
213 alert('The Native Client plugin was unable to load');
216 startupTimeout = setTimeout(RunTestsAfterLoad, 100);
220 // The page begins by loading the Native Client module, mandel_tiled.nexe.
221 var Init = function() {
222 // Record the Native Client module that was returned so that we can
223 // invoke methods on it quickly.
224 plugin = document.getElementById('nacl');
225 // After ensuring the Native Client module has loaded, run the tests.
231 <body onload=
"Init();">
232 <h1> Mandelbrot: JavaScript versus Tiled Native Client
</h1>
233 <table cellpadding=
5%
summary=
"Control panel on left, images on right">
236 <table border=
5 cellpadding=
5%
summary=
"Values and buttons for control">
238 <td colspan=
2 align=center
> <b> Control Panel
</b> </td>
241 <td align=center
> Canvas width
<br/> (in pixels)
</td>
243 <input type=
"text" value=
100 size=
5 id=
"canvas_width" />
247 <td align=center
> Tile width
<br/> (in pixels)
</td>
249 <input type=
"text" value=
100 size=
5 id=
"tile_width" />
253 <td colspan=
2 align=center
>
254 <input type=
"button" onclick=
"testJavaScript()"
255 value=
"Run JavaScript" />
259 <td colspan=
2 align=center
>
260 <input type=
"button" onclick=
"testNativeClient()"
261 value=
"Run Native Client" />
266 <td align=center valign=middle
>
267 <canvas id=
"js_canvas" width=
"100" height=
"100">
268 <code> <em> JavaScript
</em> </code>
271 <td align=center valign=middle
>
272 <canvas id=
"nacl_canvas" width=
"100" height=
"100">
273 <code> <em> Native Client
</em> </code>
279 <td align=center
id=
"js_time"></td>
280 <td align=center
id=
"nacl_time"></td>
284 First run starts automatically. Click afterwards to re-run.
<br>
285 Warning: JavaScript with a canvas width of more than about
100 pixels
289 <embed type=
"application/x-nacl-srpc" id=
"nacl"
290 src=
"mandel_tiled.nexe" hidden=
"true" />