Skip to content

Conversation

@austinshenk
Copy link

Multiple modules in core loop through list, arrays, and objects in various ways. Some can't be improved like the while cons, but there are a number of them that could be restructured to gain quite a bit of performance for not much, or any, file size increase.

A performance test bench detailed here shows many cases where a decrementing while loop with a simple conditional is the fastest looping structure.

var i=arr.length; while (i--) {}

I know this can't always be achieved given the functionality of the loop, but in the worst case we can ensure small improvements. For example, I've found various cases where a for-loop's length could be cached so it is not having to be calculated every iteration. It sounds small, but it even has better performance.

I'm planning to implement and test many of the areas I've found and report on the results for performance and also verifying functionality was not altered.

- convert forward iterating while loop into a reverse iterating one
@austinshenk
Copy link
Author

I tested the performance of the String.reverse function by creating a dummy 1 million length string.

var len = 1000000;
  var lorem = "";
  while (len--) {
    lorem += "a";
  }

I then setup tests to check the original performance to the new performance I recently committed in 79b0673. Below is a screenshot of the console timers for the function calls.

capture

I ran them 3 times as that is the suggested way to see the cached and uncached run times of a function. The performance difference is quite significant and similar results are seen on smaller sets. I also verified the function's results were not altered by using an alphabet string. I have not verified the higher and lower order characters yet, but was planning to do that.

austinshenk added 3 commits October 24, 2018 11:02
@austinshenk
Copy link
Author

Did similar testing to String.map as I did with reverse. The following screen is the timing results of mapping through a 1 million character string.

image

Overall about a 2x increase in performance. I also verified its functionality was not altered.

@austinshenk
Copy link
Author

I tried out a variation of the decrementing while loop by instead making it an incrementing one with a similar conditional. Hadn't really thought of doing it this way before.

while (len-i) {}

This allows most functions to maintain their body functionality while also easily gaining the performance boost.

austinshenk added 5 commits October 24, 2018 11:35
@austinshenk
Copy link
Author

Performance results of String's foldl, filter, and toInt. I didn't see the performance increase for foldl like I saw for the other functions which was a little weird. toInt has a little bit of a ceiling as once you get a number that equates past infinity it runs really fast.

All of these functions were tested against a 1 million character string and running against the same inputs.

string_filter
string_foldl
string_toint

@robinheghan
Copy link
Contributor

Nice! Which browsers have you tested this on?

@austinshenk
Copy link
Author

I've been testing this just on Chrome. I want to setup some test cases on an online performance tester so I can test it in multiple browsers and multiple platforms.

@austinshenk
Copy link
Author

I was taking a look at String.mapn's implementation today and realized that it is constructing an array out of the mapping's results and then converting that to a list. I wonder if we could possibly half that operation time by just constructing a List directly from the map results. I had to learn the cons structure to figure this one out, but it is a first pass.

var _List_map2 = F3(function(f, xs, ys)
{
	var list;
	if (xs.b && ys.b) {		
		for (var list = _List_Cons(A2(f, xs.a, ys.a), _List_Nil), previousCons = list, currentCons = null; xs.b && ys.b; xs = xs.b, ys = ys.b) // WHILE_CONSES
		{
			currentCons = _List_Cons(A2(f, xs.a, ys.a), _List_Nil);
			previousCons.b = currentCons
			previousCons = currentCons
		}
	} else {
		list = _List_Nil;
	}
	return list;
});

I haven't tested it at all, but it should construct the cons structure for a list as it iterates through the provided list cons.

@evancz
Copy link
Member

evancz commented Nov 9, 2018

It is really risky to change a bunch of things like this, so I think the next step should be:

  1. Benchmark individual functions
  2. Get results in many browsers
  3. Post results on https://discourse.elm-lang.org/

If the results show good results on certain specific functions, they may make sense as individual pull requests. That way they can be considered in isolation from other changes which may not have as good results, or may be different for some other reason. One aspect to consider is that JS VMs change over time, so it may be reasonable to just leave things as is knowing that whatever moment we optimize things, it may be different down the line.

Anyway, in the meantime, I think it makes sense to close here and try to do those three steps.

@evancz evancz closed this Nov 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants