Can loop unrolling or duff's help this situation? - javascript

I am using this bit of code in order to reformat some large ajax responseText into good binary data. It works, albeit slow.
The data that I am working with can be as large as 8-10 megs.
I need to get this code to be absolutely efficient. How would loop unrolling or Duff's device be applied to this code while still keeping my binary data intact, or does anyone see anything that can be changed that would help increase it's speed?
var ff = [];
var mx = text.length;
var scc= String.fromCharCode;
for (var z = 0; z < mx; z++) {
ff[z] = scc(text.charCodeAt(z) & 255);
}
var b = ff.join("");
this.fp=b;
return b;
Thanks
Pat

Your time hog isn't the loop. It's this: ff[z] = scc(text.charCodeAt(z) & 255); Are you incrementally growing ff? That will be a pig, guaranteed.
If you just run it under the debugger and pause it, I bet you will see it in the process of growing ff. Pre-allocate.

Convert the data to a JSON array on the server. 8/10 megabytes will take a long time even with a native JSON engine. I'm not sure why a JS application needs 8/10 megs of data in it. If you are downloading to the client's device, convert it to a format they expect and just link to it. They can download and process it themselves then.

Related

Javascript animation and optimization

I'm using java to generate javascript code that does various animations on a canvas.
My resulting javascript code is already getting large enough that the animation smoothness is suffering. The "draw" method that gets continually called takes long enough to run to notice the pause between frames. In the generated HTML there's already over 4,000 lines of code. So I'm looking for optimization tips.
Noting that the javascript code is mostly java generated, is it faster for the browser to execute this:
for( var i = 0; i < 4; i++ ) {
drawNumber(i);
}
Or to have java generate this?:
drawNumber(0);
drawNumber(1);
drawNumber(2);
drawNumber(3);
I prefer the latter because it makes the code more obscure.
Is it better to do:
var x = (2+1) * (2+1);
Or
var a = (2+1);
var x = a * a;
Of course the first has more math operations, but I don't know if declaring a new variable is more costly.

Javascript array 100000 x 100000 - kill my browser

I'm trying to construct such array ( Matrix ):
var arr = [];
var matrix_size = 100000;
var start_time = Math.round(new Date().getTime()) / 1000.0;
for( var i = 0; i < matrix_size ; i++ ) {
var row = [];
for( var j = 0; j < matrix_size; j++ ) {
row.push( 0 );
}
arr.push( row );
if ( counter % 10 == 0 ) {
var stop_time = Math.round(new Date().getTime()) / 1000.0;
var speed_time = stop_time - start_time;
var speed = i / speed_time; // m / s
var remain = matrix_size - i;
var remain_time = remain / speed;
console.log("Ready: " + i + " rows; remain: " + remain + "; speed: " + speed + "; remain_time: " + remain_time + "s.");
}
}
var stop_time = Math.round(new Date().getTime()) / 1000.0;
var speed_time = stop_time - start_time;
console.log( "Time: " + speed_time + " s. ");
matrix_size 1000 - 0.1700000762939453 seconds
matrix_size 10000 - 8.978000164031982 seconds
matrix_size 100000 - stuck
Ready: 1020 rows; remain: 98980; speed: 40.255742648097055; remain_time: 2458.7796296605875s.
Is it really such large? What is the right math for power of browser in such case?
Actually, me needs 500,000 x 500,000 array. Not with just zeros, but real float values. Am I need to use server side in this situation?
500Kx500K is way too much for Javascript to handle (and big enough for a reasonable computer to choke on it), but if you're still willing to work with huge datasets on the client side, I suggest you look into this: http://square.github.io/crossfilter/
Crossfilter is a JavaScript library for exploring large multivariate
datasets in the browser. Crossfilter supports extremely fast (<30ms)
interaction with coordinated views, even with datasets containing a
million or more records.
This won't solve your problem, but hopefully it'll point you in the right direction. I would suggest to break up your datasets into multiple parts and work on them separately. It is usually wiser to work on small chunks of data rather than huge datasets.
500,000 x 500,000 is 250 billion values. Each number in javascript is 8 bytes (according to a quick Google search at least).
In order to just store only the numbers in memory, you'll need over 1862.65 GB of memory (not counting any of the overhead involved in having the array, the browser, the javascript engine, etc).
Even server-side solutions would have issues with that much data. You should spend time re-evaluating your problem, and finding ways to reduce your data set earlier on.
As others have pointed out in comments a 500K x 500K matrice of doubles is going to be roughly 1.8 To of memory.
There is actually no chance you'll be able to handle that. But the upside is that there is probably no chance that you have that much data to process. And in the browser? I wonder how you would have gotten the data there in the first place!
You haven't described the actual problem that you're trying to solve, so it's hard to help you. A few random tips:
Your matrice may have a 500K dimension but it's probably mostly empty. You should look into using a sparse data structure and algorithms. A sparse datastructure doesn't store all entries in memory. Only those that are not empty.
If you work on large amount of data you should try to process it in a streaming fashion. That is: on slices of data, never loading the whole dataset in memory. That won't make it faster, but it can make it doable.
I would recommend using a database to formulate your data. You will be able to handle computational requirements by leveraging the power of a database since your matrix is so large. You can then query the DB and use server side code (PHP, Python, Java etc) to build a JSON object and traverse your data that way. Hope that helps you.
All JavaScript numbers are double-precision floating point numbers, meaning 8 bytes each. 500K x 500K x 8B turns out to be approximately 2000 GB of memory. So the "power of browser" needed in this case will be a web browser running on a machine with over 2000GB of memory, and a browser whose JavaScript memory manager will support that amount (Chrome's V8 engine starts struggling, in my experience, around 2GB).

Coursera Node.js Fibonacci implementation hanging

I am currently doing program 2 for the startup engineering course offered on coursera
I'm programming using and ubuntu instance using Amazon web services and my programming is constantly hanging. There might be something wrong with my node.js program but I can't seem to locate it.
This program is meant to produce the first 100 Fibonacci numbers separated with commas.
#! /usr/bin/env node
//calculation
var fibonacci = function(n){
if(n < 1){return 0;}
else if(n == 1 || n == 2){return 1;}
else if(n > 2){return fibonacci(n - 1) + fibonacci(n-2);}
};
//put in array
var firstkfib = function(k){
var i;
var arr = [];
for(i = 1; i <= k; i++){
arr.push(fibonacci(i));
}
return arr
};
//print
var format = function(arr){
return arr.join(",");
};
var k = 100;
console.log("firstkfib(" + k +")");
console.log(format(firstkfib(k)));
The only output I get is
ubuntu#ip-172-31-30-245:~$ node fib.js
firstkfib(100)
and then the program hangs
I don't know if you are familiar with Time complexity and algorithmic analysis, but, it turns out that your program has an exponential running time. This basically means that, as the input increases, the time it takes to run your program increases exponentially. (If my explanation is not very clear, check this link)
It turns out that this sort of running time is extremely slow. For example, if it takes 1 ms to run your program for k=1, it would take 2^100 ms to run it for k=100. This turns out to be a ridiculously big number.
In any case, as Zhehao points out, the solution is to save the value of fib(n-1) and fib(n-2) (in an array, for example), and reuse it to compute fib(n). Check out this video lecture from MIT (the first 15 mins) on how to do it.
You may want to try printing out the numbers as they are being computed, instead of printing out the entire list at the end. It's possible that the computation is hanging somewhere along the line.
On another note, this is probably the most inefficient way of computing a list of fibonacci numbers. You compute fibonacci(n) and then fibonacci(n+1) without reusing any of the work from the previous computation. You may want to go back and rethink your method. There's a much faster and simpler iterative method.
writing intense computational code in nodeJS leads to blocking. since Fibonacci is an intense computational code so might end up blocking.

how can website javascript code using same input data compute a different result depending on visitor?

The javascript code snippet below is on a website. Recently I've observed the code can produce different results for a visitor on the website than I obtain from my computer using the exact same data that the visitor input to the website. This seems to be visitor dependent (some visitors are fine). I've tried several computers/operating systems in my office, and they all produce the same (correct) results as each other, derived from the visitor's input data in question.
Part of the results (not shown below) provided by the website is a plot of the user's entered data, which I observe is always correct, so I know the visitor's input data they entered into the website (from which the javascript computation uses to compute a result) are interpreted correctly by their machine (I can see the plot the user receives (generated by auto-PDF email), and the same data entered in my computer produces the exact same plot for the entered data; just the results derived from this data are different).
In one case I analyzed, the visitor's incorrect data, mysteriously, was always a factor of 1.3 lower than the correct result. It doesn't seem like a rounding error or difference in 32b vs 64b OS.
Any ideas what could be causing such a thing? Is the code below not robust for all versions of javascript, or could different javascript versions product different results (seems hard to believe, but I'm using some fancy math below, maybe one of the mat functions is antiquated). Unfortunately I don't have access to a machine producing incorrect data to troubleshoot. I also don't know anything about the machine/OS/platform used by visitors (could be anything). Any ideas appreciated. I'm not that experienced with javascript (it could be something obvious below).
Thanks in advance.
function calculate(){
var fc=document.abcform.CF.value*1;
var of = new Array(20);
var pn = new Array(20);
var pj = new Array(19);
var cbox = new Array(20);
var alpha;
var con;
var segment;
var subttl=0;
of[0]=document.abcform.OS1.value*1; pn[0]=document.abcform.abc1.value*1;
of[1]=document.abcform.OS2.value*1; pn[1]=document.abcform.abc2.value*1;
of[2]=document.abcform.OS3.value*1; pn[2]=document.abcform.abc3.value*1;
of[3]=document.abcform.OS4.value*1; pn[3]=document.abcform.abc4.value*1;
of[4]=document.abcform.OS5.value*1; pn[4]=document.abcform.abc5.value*1;
of[5]=document.abcform.OS6.value*1; pn[5]=document.abcform.abc6.value*1;
of[6]=document.abcform.OS7.value*1; pn[6]=document.abcform.abc7.value*1;
of[7]=document.abcform.OS8.value*1; pn[7]=document.abcform.abc8.value*1;
of[8]=document.abcform.OS9.value*1; pn[8]=document.abcform.abc9.value*1;
of[9]=document.abcform.OS10.value*1; pn[9]=document.abcform.abc10.value*1;
of[10]=document.abcform.OS11.value*1; pn[10]=document.abcform.abc11.value*1;
of[11]=document.abcform.OS12.value*1; pn[11]=document.abcform.abc12.value*1;
of[12]=document.abcform.OS13.value*1; pn[12]=document.abcform.abc13.value*1;
of[13]=document.abcform.OS14.value*1; pn[13]=document.abcform.abc14.value*1;
of[14]=document.abcform.OS15.value*1; pn[14]=document.abcform.abc15.value*1;
of[15]=document.abcform.OS16.value*1; pn[15]=document.abcform.abc16.value*1;
of[16]=document.abcform.OS17.value*1; pn[16]=document.abcform.abc17.value*1;
of[17]=document.abcform.OS18.value*1; pn[17]=document.abcform.abc18.value*1;
of[18]=document.abcform.OS19.value*1; pn[18]=document.abcform.abc19.value*1;
of[19]=document.abcform.OS20.value*1; pn[19]=document.abcform.abc20.value*1;
cbox[0]=document.abcform.c1.checked; cbox[1]=document.abcform.c2.checked; cbox[2]=document.abcform.c3.checked;
cbox[3]=document.abcform.c4.checked; cbox[4]=document.abcform.c5.checked; cbox[5]=document.abcform.c6.checked;
cbox[6]=document.abcform.c7.checked; cbox[7]=document.abcform.c8.checked; cbox[8]=document.abcform.c9.checked;
cbox[9]=document.abcform.c10.checked; cbox[10]=document.abcform.c11.checked; cbox[11]=document.abcform.c12.checked;
cbox[12]=document.abcform.c13.checked; cbox[13]=document.abcform.c14.checked; cbox[14]=document.abcform.c15.checked;
cbox[15]=document.abcform.c16.checked; cbox[16]=document.abcform.c17.checked; cbox[17]=document.abcform.c18.checked;
cbox[18]=document.abcform.c19.checked; cbox[19]=document.abcform.c20.checked;
for (var i = 0; i <= 18; i++) { pj[i] = '' }
for (var j = 1; j <= 19; j++){
if (j == 1 || cbox[j]) {
alpha = (pn[j-1] - pn[j])/(10*(Math.LOG10E*Math.log(of[j]/of[j-1])));
con = (Math.pow(of[j-1],alpha))*(Math.pow(10,0.1*pn[j-1]));
if ((alpha <= (1 + 1e-14)) && (alpha >= (1 - 1e-14))) {
segment = con*Math.log(of[j]/of[j-1]); }
else { segment = (con/(1-alpha))*(Math.pow(of[j],1-alpha)-Math.pow(of[j-1],1-alpha)); }
pj[j-1] = round(1E12*(Math.sqrt(2*segment))/(2*Math.PI*fc));
subttl = subttl + Math.pow(pj[j-1],2);
} else {break;}
}
document.abcform.pj1.value=pj[0]; document.abcform.pj2.value=pj[1]; document.abcform.pj3.value=pj[2];
document.abcform.pj4.value=pj[3]; document.abcform.pj5.value=pj[4]; document.abcform.pj6.value=pj[5];
document.abcform.pj7.value=pj[6]; document.abcform.pj8.value=pj[7]; document.abcform.pj9.value=pj[8];
document.abcform.pj10.value=pj[9]; document.abcform.pj11.value=pj[10]; document.abcform.pj12.value=pj[11];
document.abcform.pj13.value=pj[12]; document.abcform.pj14.value=pj[13]; document.abcform.pj15.value=pj[14];
document.abcform.pj16.value=pj[15]; document.abcform.pj17.value=pj[16]; document.abcform.pj18.value=pj[17];
document.abcform.pj19.value=pj[18];
document.abcform.tj.value=round(Math.sqrt(subttl));
}
function round(x) { return Math.round(x*100000)/100000; }
Doesn't seem like a rounding error or
difference in 32b vs 64b OS.
Why not... this is exactly what it seems like. Maybe even a 16bit machine for that matter. You are doing lots of crazy floating point operations -- they typically perform lots of truncation and rounding.
Option two: The log or pow or sqrt functions are implemented differently on different browsers. Solution -- implement your own and see if you get the same "different" results.
Definitely sounds like rounding errors to me, and it doesn't matter what the underlying elements are (64 bit, 32 bit, implementations of pow, etc).
Consider:
alpha = (pn[j-1] - pn[j])/(10*(Math.LOG10E*Math.log(of[j]/of[j-1])));
(Math.pow(of[j-1],alpha))*(Math.pow(10,0.1*pn[j-1]))
That right there can have different results, since it's all floating math. You'll have to either use ints, or something like BigNumber.
In cases like that printf debugging is sometimes helpful - print out all the intermediate values (like alpha) for all the iterations and then compare the outputs to see where they are different. Gives you a starting point.
After debugging, it turns out this is related to a loss of precision by converting to scientific notation in code not shown above. Thus, it's a non-javascript issue (e.g. user error). Thanks for all of the insight above though.

How to prevent "A script on this page is causing Internet Explorer to run slowly" without changing MaxScriptStatements in the registry?

We are using Bing and/or Google javascript map controls, sometimes with large numbers of dynamically alterable overlays.
I have read http://support.microsoft.com/kb/175500/en-us and know how to set the MaxScriptStatments registry key.
Problem is we do not want to programmatically set this or any other registry key on users' computers but would rather achieve the same effect some other way.
Is there another way?
Hardly anything you can do besides making your script "lighter". Try to profile it and figure out where the heaviest crunching takes place, then try to optimize those parts, break them down into smaller components, call the next component with a timeout after the previous one has finished and so on. Basically, give the control back to the browser every once in a while, don't crunch everything in one function call.
Generally a long running script is encountered in code that is looping.
If you're having to loop over a large collection of data and it can be done asynchronously--akin to another thread then move the processing to a webworker(http://www.w3schools.com/HTML/html5_webworkers.asp).
If you cannot or do not want to use a webworker then you can find your main loop that is causing the long running script and you can give it a max number of loops and then cause it to yield back to the client using setTimeout.
Bad: (thingToProcess may be too large, resulting in a long running script)
function Process(thingToProcess){
var i;
for(i=0; i < thingToProcess.length; i++){
//process here
}
}
Good: (only allows 100 iterations before yielding back)
function Process(thingToProcess, start){
var i;
if(!start) start = 0;
for(i=start; i < thingToProcess.length && i - start < 100; i++){
//process here
}
if(i < thingToProcess.length) //still more to process
setTimeout(function(){Process(thingToProcess, i);}, 0);
}
Both can be called in the same way:
Process(myCollectionToProcess);

Categories