Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed problem with large files on Raspberry Pi 2 #108

Closed
mayhem2408 opened this issue Dec 10, 2016 · 20 comments
Closed

Speed problem with large files on Raspberry Pi 2 #108

mayhem2408 opened this issue Dec 10, 2016 · 20 comments

Comments

@mayhem2408
Copy link

mayhem2408 commented Dec 10, 2016

I have been experiencing a speed issue with CNC V1.8.7 on my Raspberry pi 2. Specifically with large files. I have found that CNC is unable the feed to data to my Arduino fast enough and the planner buffer and serial bufer is hovering around empty. However if I have just a small portion of the same G-code file, CNC has no problem feeding it to my Arduino and the planner buffer staying nice and full and the serial buffer is about 60-80% full most of the time.

One example is a Laser Raster which is 6.6MB in size and contains 357,000 lines of G-code. From the second it starts, CNC is struggling to feed the data fast enough from the raspberry pi to the Arduino. However if I take the first 15,000 line of that same file, it feed to data fast enough to keep the planner buffer full.

This same file running on the Windows version on the same Arduino has no problems. It is only a problem on the raspberry pi. Has anyone else experienced this.

I have attached a ZIP file which contained two G-code files. One is the full file, and one is the first 15,000 lines.
I've also attached some screen shots of the running process. As you can see, the full file has only executed 3300 lines, but the smaller file has executed 13280 lines of the same code in the same amount of time.

For reference, the full G-Code file execute cleanly on Windows CNC 1.8.7 in Windows 10 and takes about 42 minutes. But on the raspberry pi, it stutters a lot takes over 2 hours.

1-large file loaded not running
2-large file loaded running 1m30s
3-small file loaded not running
4-small file loaded running 1m30s

Zac - RIP.zip

@AustinSaintAubin
Copy link
Contributor

I have also noticed the same issue of the planer buffer always at zero as well on most if not all of my carves.

@mayhem2408
Copy link
Author

In CNC.js running GRBL 1.1, if the planner buffer is 0, that means it is full, and that's a good thing. On small files, I get 0 on the planner buffer and everything runs smooth, but on large files the buffer jumps between 14 and 15 when means GRBL is starved of data and causes it to stutter.

@mayhem2408
Copy link
Author

I've tested the same 357,000 line file using the python script 'stream.py' on my raspberry pi and it has no problem keeping up with CPU usage sitting below 5% the whole time.

@mayhem2408
Copy link
Author

I've just updated to V1.8.8 and still having the same problem.

@cheton
Copy link
Collaborator

cheton commented Dec 23, 2016

Sorry for the late, I have been so busy the last two weeks. Next week I should have time to investigate the performance issue with your large G-code files on a RPi2. I will keep you updated once I found some clues.

@cheton
Copy link
Collaborator

cheton commented Jan 4, 2017

Hi @mayhem2408,

May I know your full Grbl settings ($$), especially the followings:

$100  X-axis steps per millimeter
$101  Y-axis steps per millimeter
$102  Z-axis steps per millimeter
$110  X-axis maximum rate, mm/min
$111  Y-axis maximum rate, mm/min
$112  Z-axis maximum rate, mm/min
$120  X-axis acceleration, mm/sec^2
$121  Y-axis acceleration, mm/sec^2
$122  Z-axis acceleration, mm/sec^2

I tried "Zac - RIP - Y0-Y3.9.nc" and "Zac - RIP - Full.nc" files, but both cannot achieve the feed rate 2000 mm/min in status reports. The planner buffer is not fully utilized as well.

image

@cheton
Copy link
Collaborator

cheton commented Jan 4, 2017

I forgot to enable laser mode by altering the $32 Grbl setting with the value of 1. After setting $32=1, it can achieve the desired feed rate.

After several tries, I experienced the same issue that both planner buffer and receive buffer are not fully utilized when loading a large file (e.g. Zac-RIP-Full.nc) on RPi2, but it never happened on a powerful machine like Windows desktop or Mac Book Air.

Needs to investigate what might be affected by CPU power while handling a large size of array on RPi2.

Zac-RIP-Full.nc (on RPi2)

image

Zac-RIP-Y0-Y3.9.nc (on RPi2)

image

@cheton
Copy link
Collaborator

cheton commented Jan 4, 2017

https://gamealchemist.wordpress.com/2013/05/01/lets-get-those-javascript-arrays-to-work-fast/
Push and pop are not constant time operations

Push and pop are not constant time operations, but are taking a time proportional to the array’s length ( O(n) ), and memory fragmentation.

It might be related to the remain and sent array, which contains two copies of full G-code lines:

https://github.com/cheton/cnc/blob/master/src/app/lib/gcode-sender.js#L13

class GCodeSender extends events.EventEmitter {
    name = '';
    gcode = '';
    remain = [];
    sent = [];

If that's the root cause, it should be easy to resolve the performance issue.

@cheton
Copy link
Collaborator

cheton commented Jan 5, 2017

I made some performance improvements of reducing file loading time by removing unnecessary regular expressions when parsing G-code commands. The loading speed will be 10x faster than current release.

@mayhem2408
Copy link
Author

$32=1; Laser Mode
$100=80; X-axis steps per millimeter
$101=80; Y-axis steps per millimeter
$102=80; Z-axis steps per millimeter (Not Used on my Rig)
$110=10000; X-axis maximum rate, mm/min
$111=10000; Y-axis maximum rate, mm/min
$112=500; Z-axis maximum rate, mm/min (Not Used)
$120=1500; X-axis acceleration, mm/sec^2
$121=1500; Y-axis acceleration, mm/sec^2
$122=100; Z-axis acceleration, mm/sec^2 (Not Used)

All my engraving is done using the new M4 mode instead of M3. But that wont affect the stream.

I've just tried V1.8.12 and still having speed issues with the larger file.

@cheton
Copy link
Collaborator

cheton commented Jan 6, 2017

The code changes for performance enhancements is still under local development, it will be released in 1.8.13 or 1.9.0.

@AustinSaintAubin
Copy link
Contributor

This might be worth a read for one way to go about performance debugging on a node.js application.

@mayhem2408
Copy link
Author

@cheton I have read that the shift() method can be very slow on large arrays. I was going to have a look at the code to see if a single array and an index variable could be used instead of the two arrays with Shifts and pushes, which would mean the large array would not have to be altered once loaded. I'll wait for your next release to see how it goes.

@mayhem2408
Copy link
Author

@cheton I've also read that if you reverse() the array and then pop() off the end of the array, it is faster, but I haven't tested the theory.

@cheton
Copy link
Collaborator

cheton commented Jan 6, 2017

Just like you said, I refactored current implementation of character-counting streaming protocol using a single array (this.lines) and an index variable (this.sent). The time complexity is O(1), which should be much faster when handling a large array.

[STREAMING_PROTOCOL_CHAR_COUNTING]: () => {
    if (this.transmitDataQueue.length > 0) {
        const dataLength = this.transmitDataQueue.shift();
        this.transmitDataLength -= dataLength;
    }

    while (this.sent < this.total) {
        const line = this.lines[this.sent];
        this.transmitLine = this.transmitLine || stripLine(line);

        if (this.transmitLine.length + this.transmitDataLength >= this.transmitBufferSize) {
            break;
        }

        const gcode = this.transmitLine;
        this.transmitLine = ''; // clear transmitLine

        this.sent++;
        this.emit('change');

        if (gcode.length > 0) {
            this.transmitDataLength += gcode.length;
            this.transmitDataQueue.push(gcode.length);
            this.emit('gcode', gcode);
        } else {
            this.ack(); // Ack for empty lines
        }

        // Continue to the next line if empty
    }
}

@cheton
Copy link
Collaborator

cheton commented Jan 6, 2017

Also made significant performance improvements for gcode-parser, gcode-interpreter, and gcode-toolpath. It will speed up loading time at least 5x faster than earlier versions.

My benchmark shows that rendering a 10MB gcode file into 3D view will be reduced from 40s to 5s on Mac Book Air '12.

@mayhem2408
Copy link
Author

mayhem2408 commented Jan 7, 2017

@cheton I've downloaded and manually installed 1.8.13 from the master and WOW. What a difference. The Raspberry Pi is keeping up and with room to spare. CPU usage is now only between 20-30% and the Planner and Serial buffers are remaining full.
Full file on V1.8.12 took 2h:43m to complete.
Full file on V1.8.13 took 43minutes which is the same as the stream.py python script.

The Load and render time improvements are massive.
V1.8.12, Load took 1m:33s and Render took 2m:00s, Total 3m:33s.
V1.8.13. Load took 0m:16s and Render was took quick to see. Total 0m:16s.
Thats over 13x faster.

Well done. Awesome work.

@mayhem2408
Copy link
Author

@cheton I though i'd give it a workout with some of my larger files. The next one was 650,000 line and 12Mb. It loaded and Rendered is 33 seconds and streams with no performance hit keeping the Raspberry Pi CPU at 20-30% and buffers are full.
So I though lets really stress test this thing. 1,885,791 lines of gcode and 35Mb.
This time Google Chrome said Aw... Google chrome has run out of memory.
So I tried 998,996 lines at 19.1Mb. It loaded and the Raspberry Pi streamed it OK, but Google Chrome keeps going not responsive. I'm guessing thats a Chrome limitation and not a great deal you can do about that.

@cheton
Copy link
Collaborator

cheton commented Jan 8, 2017

Can you try to close the G-code widget? This widget may also consume a lot of memory while loading a large G-code file.

A better solution is to use a so-called lazy-loading mechanism instead of processing all the lines at once, which will save a lot of memory in the browser.

@cheton
Copy link
Collaborator

cheton commented Jan 9, 2017

Fixed in 1.8.13.

For large file support (i.e. >20MB), I will create another issue for future enhancements.

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

No branches or pull requests

3 participants