Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
I've created a project for this https://github.com/rdwallis/Guess-Scheduler It is about 2x faster than the existing scheduler without a lower fps for the fibonacci sequence. I suspect that for all tasks it will be faster or the same speed (tasks that take more than .5 ms to run won't speed up) as the current scheduler and it will have very similar FPS performance. Demo site: http://rdwallis.github.io/Guess-Scheduler/ I think this can be quite easily improved to be about 4x faster than the current scheduler. It's a bit hard to work on this because it needs a full compile between tests. And obviously the test harness needs to be updated to run more than just fibonacci and to run (multiple different tasks simultaneously). I'll do a bit of improvement to this every couple of weeks until I'm confident in it and then I'll do a PR to gerrit. (Unless someone else wants to run with this.) On Wed, Jan 14, 2015 at 6:10 PM, Richard Wallis rdwal...@gmail.com wrote: It's dangerous in the current implementation because the faster job can die before a slower job messing up the estimate. The above is wrong, any task finishing will make the estimate too low (which is safe) rather than too high. On Wed, Jan 14, 2015 at 5:25 PM, Richard Wallis rdwal...@gmail.com wrote: Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? Loop count code takes this into account and only runs if the length of the task queue == 1. The second approach where you divide the TIME_SLICE by elapsed time and then multiply by how many tasks have run will work with multiple tasks at a time. It's dangerous in the current implementation because the faster job can die before a slower job messing up the estimate. But it can be made safe On Wed, Jan 14, 2015 at 5:14 PM, Thomas Broyer t.bro...@gmail.com wrote: Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? On Wednesday, January 14, 2015 at 3:07:47 PM UTC+1, Richard Wallis wrote: Just an update, there's a bug in my original implementation which causes the loopCounter to tend to increase until the task ends. After removing the bug, the performance increase is only about 8% for the fibonacci sequence. Also the safer version where the loopCounter increments by at most 1 eliminates the performance gain for the fibonacci test because the task runs 8000 to 9000 times during each loop so the loopCounter never gets anywhere close to a number that will make a difference. On Wed, Jan 14, 2015 at 2:19 PM, Richard Wallis rdwal...@gmail.com wrote: Actually in defense of adding the optimization to the current api. It can be made safe by only ever setting lastLoopCounter to min(lastLoopCounter + 1, loopCounter). That should cause similar improved performance for multiple second tasks without ever having a lower frame rate than the current scheduler. On Wed, Jan 14, 2015 at 1:41 PM, Richard Wallis rdwal...@gmail.com wrote: You can't use webworkers to process the dom / xml, or do layout which is pretty much all my long running tasks do. Agree this is too dangerous to just add to the existing api but if you added a new method scheduleConstantTime() that ran the optimization it might be useful. On Wed, Jan 14, 2015 at 1:27 PM, 'Daniel Kurka' via GWT Contributors google-web-toolkit-contributors@googlegroups.com wrote: I think we do not want to make any assumptions about runtime of any tasks since this would not work well with task that have variable runtime. If you need to do heavy calculations since browser APIs have evolved a lot you should be using web workers anyway. On Wed, Jan 14, 2015 at 11:57 AM, Richard Wallis rdwal...@gmail.com wrote: At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code
Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? On Wednesday, January 14, 2015 at 3:07:47 PM UTC+1, Richard Wallis wrote: Just an update, there's a bug in my original implementation which causes the loopCounter to tend to increase until the task ends. After removing the bug, the performance increase is only about 8% for the fibonacci sequence. Also the safer version where the loopCounter increments by at most 1 eliminates the performance gain for the fibonacci test because the task runs 8000 to 9000 times during each loop so the loopCounter never gets anywhere close to a number that will make a difference. On Wed, Jan 14, 2015 at 2:19 PM, Richard Wallis rdwal...@gmail.com wrote: Actually in defense of adding the optimization to the current api. It can be made safe by only ever setting lastLoopCounter to min(lastLoopCounter + 1, loopCounter). That should cause similar improved performance for multiple second tasks without ever having a lower frame rate than the current scheduler. On Wed, Jan 14, 2015 at 1:41 PM, Richard Wallis rdwal...@gmail.com wrote: You can't use webworkers to process the dom / xml, or do layout which is pretty much all my long running tasks do. Agree this is too dangerous to just add to the existing api but if you added a new method scheduleConstantTime() that ran the optimization it might be useful. On Wed, Jan 14, 2015 at 1:27 PM, 'Daniel Kurka' via GWT Contributors google-web-toolkit-contributors@googlegroups.com wrote: I think we do not want to make any assumptions about runtime of any tasks since this would not work well with task that have variable runtime. If you need to do heavy calculations since browser APIs have evolved a lot you should be using web workers anyway. On Wed, Jan 14, 2015 at 11:57 AM, Richard Wallis rdwal...@gmail.com wrote: At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code below, (and maybe someone to take ownership of this and do a PR to gerrit on my behalf) In SchedulerImpl replace the current runRepeatingTasks method with this: (lastLoopCount is a private int field); /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration duration = createDuration(); int loopCount = 0; outer: while (duration.elapsedMillis() TIME_SLICE) { if (length == 1) { while (lastLoopCount-- 0 ) { if (!tasks.get(0).executeRepeating()) { tasks.set(0, null); canceledSomeTasks = true; break outer; } loopCount += 1; } } boolean executedSomeTask = false; for (int i = 0; i length; i++) { assert tasks.length() == length : Working array length changed + tasks.length() + != + length; Task t = tasks.get(i); if (t == null) { continue; } executedSomeTask = true; assert t.isRepeating() : Found a non-repeating Task; if (!t.executeRepeating()) { tasks.set(i, null); canceledSomeTasks = true; } loopCount += 1; } if (!executedSomeTask) { // no work left to do, break to avoid busy waiting until TIME_SLICE is reached break; } } if (length == 1) { lastLoopCount = loopCount; } if (canceledSomeTasks) { lastLoopCount = 0;
Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
Still very much a draft but I've settled on two approaches: Calculating the fibonacci sequence either approach performs about 5x better than the curent scheduler. Fibonacci sequence is thousands of very short operations so it does very well the more the duration check is skipped. Real world tasks won't improve nearly as much but I think most code should get a 10 to 15% speed increase. First approach skips loops based on how many times it ran last time (This is faster than second but I think more dangerous and only works if you're running a single task): private int lastLoopCount; /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration duration = createDuration(); int loopCount = lastLoopCount; boolean skipLoop = false; if (length == 1 lastLoopCount 0) { while (lastLoopCount-- 0 ) { if (!tasks.get(0).executeRepeating()) { tasks.set(0, null); canceledSomeTasks = true; } } skipLoop = canceledSomeTasks || duration.elapsedMillis() = TIME_SLICE; } if (skipLoop) { lastLoopCount -= 2; } else { while (duration.elapsedMillis() TIME_SLICE) { boolean executedSomeTask = false; for (int i = 0; i length; i++) { assert tasks.length() == length : Working array length changed + tasks.length() + != + length; Task t = tasks.get(i); if (t == null) { continue; } executedSomeTask = true; assert t.isRepeating() : Found a non-repeating Task; if (!t.executeRepeating()) { tasks.set(i, null); canceledSomeTasks = true; } loopCount += 1; } if (!executedSomeTask) { //no work left to do, break to avoid busy waiting until TIME_SLICE is reached break; } } if (length == 1) { lastLoopCount = loopCount; } } if (canceledSomeTasks) { lastLoopCount = 0; JsArrayTask newTasks = createQueue(); // Remove tombstones for (int i = 0; i length; i++) { if (tasks.get(i) != null) { newTasks.push(tasks.get(i)); } } assert newTasks.length() length; return newTasks.length() == 0 ? null : newTasks; } else { return tasks; } } Second approach checks how much time is elapsed and how many times the task has been run and then calculates how many times the task can be run before it needs to check the elapsed time again. (This is very slightly slower than the above but can be made to work with multiple tasks and I think will be easier to make safe, although isn't safe at the moment): /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of * codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration duration = createDuration(); int runCount = 0; int quickRunCount = 0; int elapsedMillis = duration.elapsedMillis(); while ( elapsedMillis TIME_SLICE) { boolean executedSomeTask = false; for (int i = 0; i length; i++) { assert tasks.length() == length : Working array length changed + tasks.length() + != + length; Task t = tasks.get(i); if (t == null) { continue; } executedSomeTask = true; assert t.isRepeating() : Found a non-repeating Task; if (!t.executeRepeating()) { tasks.set(i, null); canceledSomeTasks = true; } } if (!executedSomeTask) { // no work left to do, break to avoid busy waiting until // TIME_SLICE is reached break; } runCount += 1; if (quickRunCount-- = 0) { elapsedMillis = duration.elapsedMillis(); if (elapsedMillis 0) { quickRunCount = (int) (((TIME_SLICE - 1) * runCount) / elapsedMillis); } } } if (canceledSomeTasks) { JsArrayTask newTasks = createQueue(); // Remove tombstones for (int i = 0; i length; i++) { if (tasks.get(i) != null) {
Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
Ah second implementation has a bug again that makes it much faster than it should be I'll post the fix and the actual speed up, if any, shortly. On Wed, Jan 14, 2015 at 5:34 PM, Richard Wallis rdwal...@gmail.com wrote: On a side note the Scheduler implentation needs to be rewritten to make it easier to provide alternative schedulers while letting those alternative schedulers use as much of the core code as possible. It would be easier to make these patches if runRepeatingTasks was protected and there was a Scheduler interface instead of an abstract class with so many nested classes. On Wed, Jan 14, 2015 at 5:25 PM, Richard Wallis rdwal...@gmail.com wrote: Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? Loop count code takes this into account and only runs if the length of the task queue == 1. The second approach where you divide the TIME_SLICE by elapsed time and then multiply by how many tasks have run will work with multiple tasks at a time. It's dangerous in the current implementation because the faster job can die before a slower job messing up the estimate. But it can be made safe On Wed, Jan 14, 2015 at 5:14 PM, Thomas Broyer t.bro...@gmail.com wrote: Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? On Wednesday, January 14, 2015 at 3:07:47 PM UTC+1, Richard Wallis wrote: Just an update, there's a bug in my original implementation which causes the loopCounter to tend to increase until the task ends. After removing the bug, the performance increase is only about 8% for the fibonacci sequence. Also the safer version where the loopCounter increments by at most 1 eliminates the performance gain for the fibonacci test because the task runs 8000 to 9000 times during each loop so the loopCounter never gets anywhere close to a number that will make a difference. On Wed, Jan 14, 2015 at 2:19 PM, Richard Wallis rdwal...@gmail.com wrote: Actually in defense of adding the optimization to the current api. It can be made safe by only ever setting lastLoopCounter to min(lastLoopCounter + 1, loopCounter). That should cause similar improved performance for multiple second tasks without ever having a lower frame rate than the current scheduler. On Wed, Jan 14, 2015 at 1:41 PM, Richard Wallis rdwal...@gmail.com wrote: You can't use webworkers to process the dom / xml, or do layout which is pretty much all my long running tasks do. Agree this is too dangerous to just add to the existing api but if you added a new method scheduleConstantTime() that ran the optimization it might be useful. On Wed, Jan 14, 2015 at 1:27 PM, 'Daniel Kurka' via GWT Contributors google-web-toolkit-contributors@googlegroups.com wrote: I think we do not want to make any assumptions about runtime of any tasks since this would not work well with task that have variable runtime. If you need to do heavy calculations since browser APIs have evolved a lot you should be using web workers anyway. On Wed, Jan 14, 2015 at 11:57 AM, Richard Wallis rdwal...@gmail.com wrote: At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code below, (and maybe someone to take ownership of this and do a PR to gerrit on my behalf) In SchedulerImpl replace the current runRepeatingTasks method with this: (lastLoopCount is a private int field); /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration
Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
On a side note the Scheduler implentation needs to be rewritten to make it easier to provide alternative schedulers while letting those alternative schedulers use as much of the core code as possible. It would be easier to make these patches if runRepeatingTasks was protected and there was a Scheduler interface instead of an abstract class with so many nested classes. On Wed, Jan 14, 2015 at 5:25 PM, Richard Wallis rdwal...@gmail.com wrote: Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? Loop count code takes this into account and only runs if the length of the task queue == 1. The second approach where you divide the TIME_SLICE by elapsed time and then multiply by how many tasks have run will work with multiple tasks at a time. It's dangerous in the current implementation because the faster job can die before a slower job messing up the estimate. But it can be made safe On Wed, Jan 14, 2015 at 5:14 PM, Thomas Broyer t.bro...@gmail.com wrote: Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? On Wednesday, January 14, 2015 at 3:07:47 PM UTC+1, Richard Wallis wrote: Just an update, there's a bug in my original implementation which causes the loopCounter to tend to increase until the task ends. After removing the bug, the performance increase is only about 8% for the fibonacci sequence. Also the safer version where the loopCounter increments by at most 1 eliminates the performance gain for the fibonacci test because the task runs 8000 to 9000 times during each loop so the loopCounter never gets anywhere close to a number that will make a difference. On Wed, Jan 14, 2015 at 2:19 PM, Richard Wallis rdwal...@gmail.com wrote: Actually in defense of adding the optimization to the current api. It can be made safe by only ever setting lastLoopCounter to min(lastLoopCounter + 1, loopCounter). That should cause similar improved performance for multiple second tasks without ever having a lower frame rate than the current scheduler. On Wed, Jan 14, 2015 at 1:41 PM, Richard Wallis rdwal...@gmail.com wrote: You can't use webworkers to process the dom / xml, or do layout which is pretty much all my long running tasks do. Agree this is too dangerous to just add to the existing api but if you added a new method scheduleConstantTime() that ran the optimization it might be useful. On Wed, Jan 14, 2015 at 1:27 PM, 'Daniel Kurka' via GWT Contributors google-web-toolkit-contributors@googlegroups.com wrote: I think we do not want to make any assumptions about runtime of any tasks since this would not work well with task that have variable runtime. If you need to do heavy calculations since browser APIs have evolved a lot you should be using web workers anyway. On Wed, Jan 14, 2015 at 11:57 AM, Richard Wallis rdwal...@gmail.com wrote: At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code below, (and maybe someone to take ownership of this and do a PR to gerrit on my behalf) In SchedulerImpl replace the current runRepeatingTasks method with this: (lastLoopCount is a private int field); /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration duration = createDuration(); int loopCount = 0; outer: while (duration.elapsedMillis() TIME_SLICE) { if (length == 1) { while (lastLoopCount-- 0 ) { if
Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
It's dangerous in the current implementation because the faster job can die before a slower job messing up the estimate. The above is wrong, any task finishing will make the estimate too low (which is safe) rather than too high. On Wed, Jan 14, 2015 at 5:25 PM, Richard Wallis rdwal...@gmail.com wrote: Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? Loop count code takes this into account and only runs if the length of the task queue == 1. The second approach where you divide the TIME_SLICE by elapsed time and then multiply by how many tasks have run will work with multiple tasks at a time. It's dangerous in the current implementation because the faster job can die before a slower job messing up the estimate. But it can be made safe On Wed, Jan 14, 2015 at 5:14 PM, Thomas Broyer t.bro...@gmail.com wrote: Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? On Wednesday, January 14, 2015 at 3:07:47 PM UTC+1, Richard Wallis wrote: Just an update, there's a bug in my original implementation which causes the loopCounter to tend to increase until the task ends. After removing the bug, the performance increase is only about 8% for the fibonacci sequence. Also the safer version where the loopCounter increments by at most 1 eliminates the performance gain for the fibonacci test because the task runs 8000 to 9000 times during each loop so the loopCounter never gets anywhere close to a number that will make a difference. On Wed, Jan 14, 2015 at 2:19 PM, Richard Wallis rdwal...@gmail.com wrote: Actually in defense of adding the optimization to the current api. It can be made safe by only ever setting lastLoopCounter to min(lastLoopCounter + 1, loopCounter). That should cause similar improved performance for multiple second tasks without ever having a lower frame rate than the current scheduler. On Wed, Jan 14, 2015 at 1:41 PM, Richard Wallis rdwal...@gmail.com wrote: You can't use webworkers to process the dom / xml, or do layout which is pretty much all my long running tasks do. Agree this is too dangerous to just add to the existing api but if you added a new method scheduleConstantTime() that ran the optimization it might be useful. On Wed, Jan 14, 2015 at 1:27 PM, 'Daniel Kurka' via GWT Contributors google-web-toolkit-contributors@googlegroups.com wrote: I think we do not want to make any assumptions about runtime of any tasks since this would not work well with task that have variable runtime. If you need to do heavy calculations since browser APIs have evolved a lot you should be using web workers anyway. On Wed, Jan 14, 2015 at 11:57 AM, Richard Wallis rdwal...@gmail.com wrote: At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code below, (and maybe someone to take ownership of this and do a PR to gerrit on my behalf) In SchedulerImpl replace the current runRepeatingTasks method with this: (lastLoopCount is a private int field); /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration duration = createDuration(); int loopCount = 0; outer: while (duration.elapsedMillis() TIME_SLICE) { if (length == 1) { while (lastLoopCount-- 0 ) { if (!tasks.get(0).executeRepeating()) { tasks.set(0, null); canceledSomeTasks = true; break outer;
Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
Fixing the bug didn't change the performance noticably: Bug fix is: quickRunCount = (int) (((TIME_SLICE - 1) * runCount) / elapsedMillis); becomes: quickRunCount = (int) (((TIME_SLICE - 1) * runCount) / elapsedMillis) - runCount; On Wed, Jan 14, 2015 at 5:37 PM, Richard Wallis rdwal...@gmail.com wrote: Ah second implementation has a bug again that makes it much faster than it should be I'll post the fix and the actual speed up, if any, shortly. On Wed, Jan 14, 2015 at 5:34 PM, Richard Wallis rdwal...@gmail.com wrote: On a side note the Scheduler implentation needs to be rewritten to make it easier to provide alternative schedulers while letting those alternative schedulers use as much of the core code as possible. It would be easier to make these patches if runRepeatingTasks was protected and there was a Scheduler interface instead of an abstract class with so many nested classes. On Wed, Jan 14, 2015 at 5:25 PM, Richard Wallis rdwal...@gmail.com wrote: Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? Loop count code takes this into account and only runs if the length of the task queue == 1. The second approach where you divide the TIME_SLICE by elapsed time and then multiply by how many tasks have run will work with multiple tasks at a time. It's dangerous in the current implementation because the faster job can die before a slower job messing up the estimate. But it can be made safe On Wed, Jan 14, 2015 at 5:14 PM, Thomas Broyer t.bro...@gmail.com wrote: Also, your approach is assuming that all tasks in the queue are the same task that needs repeating. But what if I schedule 2 incremental tasks? On Wednesday, January 14, 2015 at 3:07:47 PM UTC+1, Richard Wallis wrote: Just an update, there's a bug in my original implementation which causes the loopCounter to tend to increase until the task ends. After removing the bug, the performance increase is only about 8% for the fibonacci sequence. Also the safer version where the loopCounter increments by at most 1 eliminates the performance gain for the fibonacci test because the task runs 8000 to 9000 times during each loop so the loopCounter never gets anywhere close to a number that will make a difference. On Wed, Jan 14, 2015 at 2:19 PM, Richard Wallis rdwal...@gmail.com wrote: Actually in defense of adding the optimization to the current api. It can be made safe by only ever setting lastLoopCounter to min(lastLoopCounter + 1, loopCounter). That should cause similar improved performance for multiple second tasks without ever having a lower frame rate than the current scheduler. On Wed, Jan 14, 2015 at 1:41 PM, Richard Wallis rdwal...@gmail.com wrote: You can't use webworkers to process the dom / xml, or do layout which is pretty much all my long running tasks do. Agree this is too dangerous to just add to the existing api but if you added a new method scheduleConstantTime() that ran the optimization it might be useful. On Wed, Jan 14, 2015 at 1:27 PM, 'Daniel Kurka' via GWT Contributors google-web-toolkit-contributors@googlegroups.com wrote: I think we do not want to make any assumptions about runtime of any tasks since this would not work well with task that have variable runtime. If you need to do heavy calculations since browser APIs have evolved a lot you should be using web workers anyway. On Wed, Jan 14, 2015 at 11:57 AM, Richard Wallis rdwal...@gmail.com wrote: At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code below, (and maybe someone to take ownership of this and do a PR to gerrit on my behalf) In SchedulerImpl replace the current runRepeatingTasks method with this: (lastLoopCount is a private int field); /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A
Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
You can't use webworkers to process the dom / xml, or do layout which is pretty much all my long running tasks do. Agree this is too dangerous to just add to the existing api but if you added a new method scheduleConstantTime() that ran the optimization it might be useful. On Wed, Jan 14, 2015 at 1:27 PM, 'Daniel Kurka' via GWT Contributors google-web-toolkit-contributors@googlegroups.com wrote: I think we do not want to make any assumptions about runtime of any tasks since this would not work well with task that have variable runtime. If you need to do heavy calculations since browser APIs have evolved a lot you should be using web workers anyway. On Wed, Jan 14, 2015 at 11:57 AM, Richard Wallis rdwal...@gmail.com wrote: At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code below, (and maybe someone to take ownership of this and do a PR to gerrit on my behalf) In SchedulerImpl replace the current runRepeatingTasks method with this: (lastLoopCount is a private int field); /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration duration = createDuration(); int loopCount = 0; outer: while (duration.elapsedMillis() TIME_SLICE) { if (length == 1) { while (lastLoopCount-- 0 ) { if (!tasks.get(0).executeRepeating()) { tasks.set(0, null); canceledSomeTasks = true; break outer; } loopCount += 1; } } boolean executedSomeTask = false; for (int i = 0; i length; i++) { assert tasks.length() == length : Working array length changed + tasks.length() + != + length; Task t = tasks.get(i); if (t == null) { continue; } executedSomeTask = true; assert t.isRepeating() : Found a non-repeating Task; if (!t.executeRepeating()) { tasks.set(i, null); canceledSomeTasks = true; } loopCount += 1; } if (!executedSomeTask) { // no work left to do, break to avoid busy waiting until TIME_SLICE is reached break; } } if (length == 1) { lastLoopCount = loopCount; } if (canceledSomeTasks) { lastLoopCount = 0; JsArrayTask newTasks = createQueue(); // Remove tombstones for (int i = 0; i length; i++) { if (tasks.get(i) != null) { newTasks.push(tasks.get(i)); } } assert newTasks.length() length; return newTasks.length() == 0 ? null : newTasks; } else { return tasks; } } -- You received this message because you are subscribed to the Google Groups GWT Contributors group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/80297aa7-c49a-4e3b-b70a-554bfaef52f0%40googlegroups.com https://groups.google.com/d/msgid/google-web-toolkit-contributors/80297aa7-c49a-4e3b-b70a-554bfaef52f0%40googlegroups.com?utm_medium=emailutm_source=footer . For more options, visit https://groups.google.com/d/optout. -- Google Germany GmbH *Dienerstr. 12* *80331 München* Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg Geschäftsführer: Graham Law, Katherine Stephens -- You received this message because you are subscribed to the
Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
I think we do not want to make any assumptions about runtime of any tasks since this would not work well with task that have variable runtime. If you need to do heavy calculations since browser APIs have evolved a lot you should be using web workers anyway. On Wed, Jan 14, 2015 at 11:57 AM, Richard Wallis rdwal...@gmail.com wrote: At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code below, (and maybe someone to take ownership of this and do a PR to gerrit on my behalf) In SchedulerImpl replace the current runRepeatingTasks method with this: (lastLoopCount is a private int field); /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration duration = createDuration(); int loopCount = 0; outer: while (duration.elapsedMillis() TIME_SLICE) { if (length == 1) { while (lastLoopCount-- 0 ) { if (!tasks.get(0).executeRepeating()) { tasks.set(0, null); canceledSomeTasks = true; break outer; } loopCount += 1; } } boolean executedSomeTask = false; for (int i = 0; i length; i++) { assert tasks.length() == length : Working array length changed + tasks.length() + != + length; Task t = tasks.get(i); if (t == null) { continue; } executedSomeTask = true; assert t.isRepeating() : Found a non-repeating Task; if (!t.executeRepeating()) { tasks.set(i, null); canceledSomeTasks = true; } loopCount += 1; } if (!executedSomeTask) { // no work left to do, break to avoid busy waiting until TIME_SLICE is reached break; } } if (length == 1) { lastLoopCount = loopCount; } if (canceledSomeTasks) { lastLoopCount = 0; JsArrayTask newTasks = createQueue(); // Remove tombstones for (int i = 0; i length; i++) { if (tasks.get(i) != null) { newTasks.push(tasks.get(i)); } } assert newTasks.length() length; return newTasks.length() == 0 ? null : newTasks; } else { return tasks; } } -- You received this message because you are subscribed to the Google Groups GWT Contributors group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/80297aa7-c49a-4e3b-b70a-554bfaef52f0%40googlegroups.com https://groups.google.com/d/msgid/google-web-toolkit-contributors/80297aa7-c49a-4e3b-b70a-554bfaef52f0%40googlegroups.com?utm_medium=emailutm_source=footer . For more options, visit https://groups.google.com/d/optout. -- Google Germany GmbH *Dienerstr. 12* *80331 München* Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg Geschäftsführer: Graham Law, Katherine Stephens -- You received this message because you are subscribed to the Google Groups GWT Contributors group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/CALLujipuOFMxCnLjdM_FER4n3-eAHPEWUQGf3AZENR_ezq255A%40mail.gmail.com. For more options, visit
[gwt-contrib] Incremental Scheduler can be about 10% faster
At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code below, (and maybe someone to take ownership of this and do a PR to gerrit on my behalf) In SchedulerImpl replace the current runRepeatingTasks method with this: (lastLoopCount is a private int field); /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration duration = createDuration(); int loopCount = 0; outer: while (duration.elapsedMillis() TIME_SLICE) { if (length == 1) { while (lastLoopCount-- 0 ) { if (!tasks.get(0).executeRepeating()) { tasks.set(0, null); canceledSomeTasks = true; break outer; } loopCount += 1; } } boolean executedSomeTask = false; for (int i = 0; i length; i++) { assert tasks.length() == length : Working array length changed + tasks.length() + != + length; Task t = tasks.get(i); if (t == null) { continue; } executedSomeTask = true; assert t.isRepeating() : Found a non-repeating Task; if (!t.executeRepeating()) { tasks.set(i, null); canceledSomeTasks = true; } loopCount += 1; } if (!executedSomeTask) { // no work left to do, break to avoid busy waiting until TIME_SLICE is reached break; } } if (length == 1) { lastLoopCount = loopCount; } if (canceledSomeTasks) { lastLoopCount = 0; JsArrayTask newTasks = createQueue(); // Remove tombstones for (int i = 0; i length; i++) { if (tasks.get(i) != null) { newTasks.push(tasks.get(i)); } } assert newTasks.length() length; return newTasks.length() == 0 ? null : newTasks; } else { return tasks; } } -- You received this message because you are subscribed to the Google Groups GWT Contributors group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/80297aa7-c49a-4e3b-b70a-554bfaef52f0%40googlegroups.com. For more options, visit https://groups.google.com/d/optout.
Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
Actually in defense of adding the optimization to the current api. It can be made safe by only ever setting lastLoopCounter to min(lastLoopCounter + 1, loopCounter). That should cause similar improved performance for multiple second tasks without ever having a lower frame rate than the current scheduler. On Wed, Jan 14, 2015 at 1:41 PM, Richard Wallis rdwal...@gmail.com wrote: You can't use webworkers to process the dom / xml, or do layout which is pretty much all my long running tasks do. Agree this is too dangerous to just add to the existing api but if you added a new method scheduleConstantTime() that ran the optimization it might be useful. On Wed, Jan 14, 2015 at 1:27 PM, 'Daniel Kurka' via GWT Contributors google-web-toolkit-contributors@googlegroups.com wrote: I think we do not want to make any assumptions about runtime of any tasks since this would not work well with task that have variable runtime. If you need to do heavy calculations since browser APIs have evolved a lot you should be using web workers anyway. On Wed, Jan 14, 2015 at 11:57 AM, Richard Wallis rdwal...@gmail.com wrote: At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code below, (and maybe someone to take ownership of this and do a PR to gerrit on my behalf) In SchedulerImpl replace the current runRepeatingTasks method with this: (lastLoopCount is a private int field); /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration duration = createDuration(); int loopCount = 0; outer: while (duration.elapsedMillis() TIME_SLICE) { if (length == 1) { while (lastLoopCount-- 0 ) { if (!tasks.get(0).executeRepeating()) { tasks.set(0, null); canceledSomeTasks = true; break outer; } loopCount += 1; } } boolean executedSomeTask = false; for (int i = 0; i length; i++) { assert tasks.length() == length : Working array length changed + tasks.length() + != + length; Task t = tasks.get(i); if (t == null) { continue; } executedSomeTask = true; assert t.isRepeating() : Found a non-repeating Task; if (!t.executeRepeating()) { tasks.set(i, null); canceledSomeTasks = true; } loopCount += 1; } if (!executedSomeTask) { // no work left to do, break to avoid busy waiting until TIME_SLICE is reached break; } } if (length == 1) { lastLoopCount = loopCount; } if (canceledSomeTasks) { lastLoopCount = 0; JsArrayTask newTasks = createQueue(); // Remove tombstones for (int i = 0; i length; i++) { if (tasks.get(i) != null) { newTasks.push(tasks.get(i)); } } assert newTasks.length() length; return newTasks.length() == 0 ? null : newTasks; } else { return tasks; } } -- You received this message because you are subscribed to the Google Groups GWT Contributors group. To unsubscribe from this group and stop receiving emails from it, send an email to google-web-toolkit-contributors+unsubscr...@googlegroups.com . To view this discussion on the web visit https://groups.google.com/d/msgid/google-web-toolkit-contributors/80297aa7-c49a-4e3b-b70a-554bfaef52f0%40googlegroups.com
Re: [gwt-contrib] Incremental Scheduler can be about 10% faster
Just an update, there's a bug in my original implementation which causes the loopCounter to tend to increase until the task ends. After removing the bug, the performance increase is only about 8% for the fibonacci sequence. Also the safer version where the loopCounter increments by at most 1 eliminates the performance gain for the fibonacci test because the task runs 8000 to 9000 times during each loop so the loopCounter never gets anywhere close to a number that will make a difference. On Wed, Jan 14, 2015 at 2:19 PM, Richard Wallis rdwal...@gmail.com wrote: Actually in defense of adding the optimization to the current api. It can be made safe by only ever setting lastLoopCounter to min(lastLoopCounter + 1, loopCounter). That should cause similar improved performance for multiple second tasks without ever having a lower frame rate than the current scheduler. On Wed, Jan 14, 2015 at 1:41 PM, Richard Wallis rdwal...@gmail.com wrote: You can't use webworkers to process the dom / xml, or do layout which is pretty much all my long running tasks do. Agree this is too dangerous to just add to the existing api but if you added a new method scheduleConstantTime() that ran the optimization it might be useful. On Wed, Jan 14, 2015 at 1:27 PM, 'Daniel Kurka' via GWT Contributors google-web-toolkit-contributors@googlegroups.com wrote: I think we do not want to make any assumptions about runtime of any tasks since this would not work well with task that have variable runtime. If you need to do heavy calculations since browser APIs have evolved a lot you should be using web workers anyway. On Wed, Jan 14, 2015 at 11:57 AM, Richard Wallis rdwal...@gmail.com wrote: At the moment, incremental scheduler runs a repeating task in a while loop that checks if its duration has exceeded 16ms and then returns control to the browser. If you assume that an incrementally scheduled task will tend to run in about the same time as it did before then you can get about a 10% speed up by counting the number of times the task ran during the last duration loop and then running the task that many times at the start (and skipping the duration check). On chrome a task that calculated the fibonacci sequence managed to calculate about 45 numbers in a second with the current scheduler and about 50 numbers in the same time with my new one below. And a realworld task that parses xml dropped from taking about 50 seconds each run to 42 seconds. Of course if the incrementally scheduled task tends to take a longer and longer time to complete on each run the oprimization might cause issues so maybe we need to create a new kind of task scheduler specifically for tasks that tend to complete their runs in a similar timeframe. I'm looking for critiscim of the code below, (and maybe someone to take ownership of this and do a PR to gerrit on my behalf) In SchedulerImpl replace the current runRepeatingTasks method with this: (lastLoopCount is a private int field); /** * Execute a list of Tasks that hold RepeatingCommands. * * @return A replacement array that is possibly a shorter copy of codetasks/code */ private JsArrayTask runRepeatingTasks(JsArrayTask tasks) { assert tasks != null : tasks; int length = tasks.length(); if (length == 0) { return null; } boolean canceledSomeTasks = false; Duration duration = createDuration(); int loopCount = 0; outer: while (duration.elapsedMillis() TIME_SLICE) { if (length == 1) { while (lastLoopCount-- 0 ) { if (!tasks.get(0).executeRepeating()) { tasks.set(0, null); canceledSomeTasks = true; break outer; } loopCount += 1; } } boolean executedSomeTask = false; for (int i = 0; i length; i++) { assert tasks.length() == length : Working array length changed + tasks.length() + != + length; Task t = tasks.get(i); if (t == null) { continue; } executedSomeTask = true; assert t.isRepeating() : Found a non-repeating Task; if (!t.executeRepeating()) { tasks.set(i, null); canceledSomeTasks = true; } loopCount += 1; } if (!executedSomeTask) { // no work left to do, break to avoid busy waiting until TIME_SLICE is reached break; } } if (length == 1) { lastLoopCount = loopCount; } if (canceledSomeTasks) { lastLoopCount = 0; JsArrayTask newTasks = createQueue(); // Remove tombstones for (int i = 0; i length; i++) { if (tasks.get(i) != null) { newTasks.push(tasks.get(i)); } } assert newTasks.length() length; return newTasks.length() ==