Detect RAM usage and stop if full

This resolves issue #1356 and add the ability for the Arduino IDE to
detect the amount of RAM allocated to a sketch and compare that to the
available RAM on each board. If RAM is more than 90% full, it will fail
on building since there is not enough free RAM for the heap and stack to
use.
This commit is contained in:
Loren M. Lang 2013-04-22 17:48:22 -07:00
parent 443d0e1f26
commit 7c87db3532
4 changed files with 95 additions and 20 deletions

View File

@ -1613,23 +1613,41 @@ public class Sketch {
protected void size(PreferencesMap prefs) throws RunnerException { protected void size(PreferencesMap prefs) throws RunnerException {
long size = 0; long textSize = 0;
String maxsizeString = prefs.get("upload.maximum_size"); long dataSize = 0;
if (maxsizeString == null) String maxTextSizeString = prefs.get("upload.maximum_size");
String maxDataSizeString = prefs.get("upload.maximum_data_size");
if (maxTextSizeString == null)
return; return;
long maxsize = Integer.parseInt(maxsizeString); long maxTextSize = Integer.parseInt(maxTextSizeString);
long maxDataSize = -1;
if(maxDataSizeString != null)
maxDataSize = Integer.parseInt(maxDataSizeString);
Sizer sizer = new Sizer(prefs); Sizer sizer = new Sizer(prefs);
try { try {
size = sizer.computeSize(); long[] sizes = sizer.computeSize();
textSize = sizes[0];
dataSize = sizes[1];
System.out.println(I18n System.out.println(I18n
.format(_("Binary sketch size: {0} bytes (of a {1} byte maximum) - {2}% used"), .format(_("Binary sketch size: {0} bytes (of a {1} byte maximum) - {2}% used"),
size, maxsize, size * 100 / maxsize)); textSize, maxTextSize, textSize * 100 / maxTextSize));
if(maxDataSize > 0) {
System.out.println(I18n
.format(_("Memory usage: {0} bytes (of a {1} byte maximum) - {2}% used"),
dataSize, maxDataSize, dataSize * 100 / maxDataSize));
} else {
System.out.println(I18n
.format(_("Memory usage: {0} bytes"),
dataSize));
}
} catch (RunnerException e) { } catch (RunnerException e) {
System.err.println(I18n.format(_("Couldn't determine program size: {0}"), System.err.println(I18n.format(_("Couldn't determine program size: {0}"),
e.getMessage())); e.getMessage()));
} }
if (size > maxsize) /* At least 10% of RAM should be reserved for stack/heap usage */
if (textSize > maxTextSize ||
(maxDataSize > 0 && dataSize > maxDataSize*9/10))
throw new RunnerException( throw new RunnerException(
_("Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it.")); _("Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it."));
} }

View File

@ -33,18 +33,30 @@ import processing.app.helpers.PreferencesMap;
import processing.app.helpers.StringReplacer; import processing.app.helpers.StringReplacer;
public class Sizer implements MessageConsumer { public class Sizer implements MessageConsumer {
private long size; private long textSize;
private long dataSize;
private long eepromSize;
private RunnerException exception; private RunnerException exception;
private PreferencesMap prefs; private PreferencesMap prefs;
private String firstLine; private String firstLine;
private Pattern pattern; private Pattern textPattern;
private Pattern dataPattern;
private Pattern eepromPattern;
public Sizer(PreferencesMap _prefs) { public Sizer(PreferencesMap _prefs) {
prefs = _prefs; prefs = _prefs;
pattern = Pattern.compile(prefs.get("recipe.size.regex")); textPattern = Pattern.compile(prefs.get("recipe.size.regex"));
dataPattern = null;
String pref = prefs.get("recipe.size.regex.data");
if(pref != null)
dataPattern = Pattern.compile(pref);
eepromPattern = null;
pref = prefs.get("recipe.size.regex.eeprom");
if(pref != null)
eepromPattern = Pattern.compile(pref);
} }
public long computeSize() throws RunnerException { public long[] computeSize() throws RunnerException {
int r = 0; int r = 0;
try { try {
@ -52,7 +64,9 @@ public class Sizer implements MessageConsumer {
String cmd[] = StringReplacer.formatAndSplit(pattern, prefs, true); String cmd[] = StringReplacer.formatAndSplit(pattern, prefs, true);
exception = null; exception = null;
size = -1; textSize = -1;
dataSize = -1;
eepromSize = -1;
Process process = Runtime.getRuntime().exec(cmd); Process process = Runtime.getRuntime().exec(cmd);
MessageSiphon in = new MessageSiphon(process.getInputStream(), this); MessageSiphon in = new MessageSiphon(process.getInputStream(), this);
MessageSiphon err = new MessageSiphon(process.getErrorStream(), this); MessageSiphon err = new MessageSiphon(process.getErrorStream(), this);
@ -77,17 +91,36 @@ public class Sizer implements MessageConsumer {
if (exception != null) if (exception != null)
throw exception; throw exception;
if (size == -1) if (textSize == -1)
throw new RunnerException(firstLine); throw new RunnerException(firstLine);
return size; return new long[] { textSize, dataSize, eepromSize };
} }
public void message(String s) { public void message(String s) {
if (firstLine == null) if (firstLine == null)
firstLine = s; firstLine = s;
Matcher matcher = pattern.matcher(s.trim()); Matcher textMatcher = textPattern.matcher(s.trim());
if (matcher.matches()) if (textMatcher.matches()) {
size = Long.parseLong(matcher.group(1)); if (textSize < 0)
textSize = 0;
textSize += Long.parseLong(textMatcher.group(1));
}
if(dataPattern != null) {
Matcher dataMatcher = dataPattern.matcher(s.trim());
if (dataMatcher.matches()) {
if (dataSize < 0)
dataSize = 0;
dataSize += Long.parseLong(dataMatcher.group(1));
}
}
if(eepromPattern != null) {
Matcher eepromMatcher = eepromPattern.matcher(s.trim());
if (eepromMatcher.matches()) {
if (eepromSize < 0)
eepromSize = 0;
eepromSize += Long.parseLong(eepromMatcher.group(1));
}
}
} }
} }

View File

@ -8,6 +8,7 @@ uno.name=Arduino Uno
uno.upload.tool=avrdude uno.upload.tool=avrdude
uno.upload.protocol=arduino uno.upload.protocol=arduino
uno.upload.maximum_size=32256 uno.upload.maximum_size=32256
uno.upload.maximum_data_size=2048
uno.upload.speed=115200 uno.upload.speed=115200
uno.bootloader.tool=avrdude uno.bootloader.tool=avrdude
@ -46,6 +47,7 @@ atmega328diecimila.build.variant=standard
atmega328diecimila.menu.cpu.atmega328=ATmega328 atmega328diecimila.menu.cpu.atmega328=ATmega328
atmega328diecimila.menu.cpu.atmega328.upload.maximum_size=30720 atmega328diecimila.menu.cpu.atmega328.upload.maximum_size=30720
atmega328diecimila.menu.cpu.atmega328.upload.maximum_data_size=2048
atmega328diecimila.menu.cpu.atmega328.upload.speed=57600 atmega328diecimila.menu.cpu.atmega328.upload.speed=57600
atmega328diecimila.menu.cpu.atmega328.bootloader.high_fuses=0xDA atmega328diecimila.menu.cpu.atmega328.bootloader.high_fuses=0xDA
@ -59,6 +61,7 @@ atmega328diecimila.menu.cpu.atmega328.build.mcu=atmega328p
atmega328diecimila.menu.cpu.atmega168=ATmega168 atmega328diecimila.menu.cpu.atmega168=ATmega168
atmega328diecimila.menu.cpu.atmega168.upload.maximum_size=14336 atmega328diecimila.menu.cpu.atmega168.upload.maximum_size=14336
atmega328diecimila.menu.cpu.atmega168.upload.maximum_data_size=1024
atmega328diecimila.menu.cpu.atmega168.upload.speed=19200 atmega328diecimila.menu.cpu.atmega168.upload.speed=19200
atmega328diecimila.menu.cpu.atmega168.bootloader.high_fuses=0xdd atmega328diecimila.menu.cpu.atmega168.bootloader.high_fuses=0xdd
@ -88,6 +91,7 @@ nano.build.variant=eightanaloginputs
nano.menu.cpu.atmega328=ATmega328 nano.menu.cpu.atmega328=ATmega328
nano.menu.cpu.atmega328.upload.maximum_size=30720 nano.menu.cpu.atmega328.upload.maximum_size=30720
nano.menu.cpu.atmega328.upload.maximum_data_size=2048
nano.menu.cpu.atmega328.upload.speed=57600 nano.menu.cpu.atmega328.upload.speed=57600
nano.menu.cpu.atmega328.bootloader.low_fuses=0xFF nano.menu.cpu.atmega328.bootloader.low_fuses=0xFF
@ -102,6 +106,7 @@ menu.cpu.nano.atmega328.build.mcu=atmega328p
nano.menu.cpu.atmega168=ATmega168 nano.menu.cpu.atmega168=ATmega168
nano.menu.cpu.atmega168.upload.maximum_size=14336 nano.menu.cpu.atmega168.upload.maximum_size=14336
nano.menu.cpu.atmega168.upload.maximum_data_size=1024
nano.menu.cpu.atmega168.upload.speed=19200 nano.menu.cpu.atmega168.upload.speed=19200
nano.menu.cpu.atmega168.bootloader.low_fuses=0xff nano.menu.cpu.atmega168.bootloader.low_fuses=0xff
@ -165,6 +170,7 @@ leonardo.name=Arduino Leonardo
leonardo.upload.tool=avrdude leonardo.upload.tool=avrdude
leonardo.upload.protocol=avr109 leonardo.upload.protocol=avr109
leonardo.upload.maximum_size=28672 leonardo.upload.maximum_size=28672
leonardo.upload.maximum_data_size=2560
leonardo.upload.speed=57600 leonardo.upload.speed=57600
leonardo.upload.disable_flushing=true leonardo.upload.disable_flushing=true
leonardo.upload.use_1200bps_touch=true leonardo.upload.use_1200bps_touch=true
@ -193,6 +199,7 @@ micro.name=Arduino Micro
micro.upload.tool=avrdude micro.upload.tool=avrdude
micro.upload.protocol=avr109 micro.upload.protocol=avr109
micro.upload.maximum_size=28672 micro.upload.maximum_size=28672
micro.upload.maximum_data_size=2560
micro.upload.speed=57600 micro.upload.speed=57600
micro.upload.disable_flushing=true micro.upload.disable_flushing=true
micro.upload.use_1200bps_touch=true micro.upload.use_1200bps_touch=true
@ -221,6 +228,7 @@ esplora.name=Arduino Esplora
esplora.upload.tool=avrdude esplora.upload.tool=avrdude
esplora.upload.protocol=avr109 esplora.upload.protocol=avr109
esplora.upload.maximum_size=28672 esplora.upload.maximum_size=28672
esplora.upload.maximum_data_size=2560
esplora.upload.speed=57600 esplora.upload.speed=57600
esplora.upload.disable_flushing=true esplora.upload.disable_flushing=true
esplora.upload.use_1200bps_touch=true esplora.upload.use_1200bps_touch=true
@ -265,6 +273,7 @@ mini.build.variant=eightanaloginputs
mini.menu.cpu.atmega328=ATmega328 mini.menu.cpu.atmega328=ATmega328
mini.menu.cpu.atmega328.upload.maximum_size=28672 mini.menu.cpu.atmega328.upload.maximum_size=28672
mini.menu.cpu.atmega328.upload.maximum_data_size=2048
mini.menu.cpu.atmega328.upload.speed=115200 mini.menu.cpu.atmega328.upload.speed=115200
mini.menu.cpu.atmega328.bootloader.high_fuses=0xd8 mini.menu.cpu.atmega328.bootloader.high_fuses=0xd8
@ -278,6 +287,7 @@ mini.menu.cpu.atmega328.build.mcu=atmega328p
mini.menu.cpu.atmega168=ATmega168 mini.menu.cpu.atmega168=ATmega168
mini.menu.cpu.atmega168.upload.maximum_size=14336 mini.menu.cpu.atmega168.upload.maximum_size=14336
mini.menu.cpu.atmega168.upload.maximum_data_size=1024
mini.menu.cpu.atmega168.upload.speed=19200 mini.menu.cpu.atmega168.upload.speed=19200
mini.menu.cpu.atmega168.bootloader.high_fuses=0xdd mini.menu.cpu.atmega168.bootloader.high_fuses=0xdd
@ -293,6 +303,7 @@ ethernet.name=Arduino Ethernet
ethernet.upload.tool=avrdude ethernet.upload.tool=avrdude
ethernet.upload.protocol=arduino ethernet.upload.protocol=arduino
ethernet.upload.maximum_size=32256 ethernet.upload.maximum_size=32256
ethernet.upload.maximum_data_size=2048
ethernet.upload.speed=115200 ethernet.upload.speed=115200
ethernet.bootloader.tool=avrdude ethernet.bootloader.tool=avrdude
@ -316,6 +327,7 @@ fio.name=Arduino Fio
fio.upload.tool=avrdude fio.upload.tool=avrdude
fio.upload.protocol=arduino fio.upload.protocol=arduino
fio.upload.maximum_size=30720 fio.upload.maximum_size=30720
fio.upload.maximum_data_size=2048
fio.upload.speed=57600 fio.upload.speed=57600
fio.bootloader.tool=avrdude fio.bootloader.tool=avrdude
@ -355,6 +367,7 @@ bt.build.variant=eightanaloginputs
## ----------------------- ## -----------------------
bt.menu.cpu.atmega328=ATmega328 bt.menu.cpu.atmega328=ATmega328
bt.menu.cpu.atmega328.upload.maximum_size=28672 bt.menu.cpu.atmega328.upload.maximum_size=28672
bt.menu.cpu.atmega328.upload.maximum_data_size=2048
bt.menu.cpu.atmega328.bootloader.high_fuses=0xd8 bt.menu.cpu.atmega328.bootloader.high_fuses=0xd8
bt.menu.cpu.atmega328.bootloader.extended_fuses=0x05 bt.menu.cpu.atmega328.bootloader.extended_fuses=0x05
@ -366,6 +379,7 @@ bt.menu.cpu.atmega328.build.mcu=atmega328p
## ----------------------- ## -----------------------
bt.menu.cpu.atmega168=ATmega168 bt.menu.cpu.atmega168=ATmega168
bt.menu.cpu.atmega168.upload.maximum_size=14336 bt.menu.cpu.atmega168.upload.maximum_size=14336
bt.menu.cpu.atmega168.upload.maximum_data_size=1024
bt.menu.cpu.atmega168.bootloader.high_fuses=0xdd bt.menu.cpu.atmega168.bootloader.high_fuses=0xdd
bt.menu.cpu.atmega168.bootloader.extended_fuses=0x00 bt.menu.cpu.atmega168.bootloader.extended_fuses=0x00
@ -380,6 +394,7 @@ LilyPadUSB.name=LilyPad Arduino USB
LilyPadUSB.upload.tool=avrdude LilyPadUSB.upload.tool=avrdude
LilyPadUSB.upload.protocol=avr109 LilyPadUSB.upload.protocol=avr109
LilyPadUSB.upload.maximum_size=28672 LilyPadUSB.upload.maximum_size=28672
LilyPadUSB.upload.maximum_data_size=2560
LilyPadUSB.upload.speed=57600 LilyPadUSB.upload.speed=57600
LilyPadUSB.upload.disable_flushing=true LilyPadUSB.upload.disable_flushing=true
LilyPadUSB.upload.use_1200bps_touch=true LilyPadUSB.upload.use_1200bps_touch=true
@ -423,6 +438,7 @@ lilypad.build.variant=standard
lilypad.menu.cpu.atmega328=ATmega328 lilypad.menu.cpu.atmega328=ATmega328
lilypad.menu.cpu.atmega328.upload.maximum_size=30720 lilypad.menu.cpu.atmega328.upload.maximum_size=30720
lilypad.menu.cpu.atmega328.upload.maximum_data_size=2048
lilypad.menu.cpu.atmega328.upload.speed=57600 lilypad.menu.cpu.atmega328.upload.speed=57600
lilypad.menu.cpu.atmega328.bootloader.low_fuses=0xFF lilypad.menu.cpu.atmega328.bootloader.low_fuses=0xFF
@ -437,6 +453,7 @@ lilypad.menu.cpu.atmega328.build.mcu=atmega328p
lilypad.menu.cpu.atmega168=ATmega168 lilypad.menu.cpu.atmega168=ATmega168
lilypad.menu.cpu.atmega168.upload.maximum_size=14336 lilypad.menu.cpu.atmega168.upload.maximum_size=14336
lilypad.menu.cpu.atmega168.upload.maximum_data_size=1024
lilypad.menu.cpu.atmega168.upload.speed=19200 lilypad.menu.cpu.atmega168.upload.speed=19200
lilypad.menu.cpu.atmega168.bootloader.low_fuses=0xe2 lilypad.menu.cpu.atmega168.bootloader.low_fuses=0xe2
@ -466,6 +483,7 @@ pro.build.variant=standard
pro.menu.cpu.16MHzatmega328=ATmega328 (5V, 16 MHz) pro.menu.cpu.16MHzatmega328=ATmega328 (5V, 16 MHz)
pro.menu.cpu.16MHzatmega328.upload.maximum_size=30720 pro.menu.cpu.16MHzatmega328.upload.maximum_size=30720
pro.menu.cpu.16MHzatmega328.upload.maximum_data_size=2048
pro.menu.cpu.16MHzatmega328.upload.speed=57600 pro.menu.cpu.16MHzatmega328.upload.speed=57600
pro.menu.cpu.16MHzatmega328.bootloader.low_fuses=0xFF pro.menu.cpu.16MHzatmega328.bootloader.low_fuses=0xFF
@ -481,6 +499,7 @@ pro.menu.cpu.16MHzatmega328.build.f_cpu=16000000L
pro.menu.cpu.8MHzatmega328=ATmega328 (3.3V, 8 MHz) pro.menu.cpu.8MHzatmega328=ATmega328 (3.3V, 8 MHz)
pro.menu.cpu.8MHzatmega328.upload.maximum_size=30720 pro.menu.cpu.8MHzatmega328.upload.maximum_size=30720
pro.menu.cpu.8MHzatmega328.upload.maximum_data_size=2048
pro.menu.cpu.8MHzatmega328.upload.speed=57600 pro.menu.cpu.8MHzatmega328.upload.speed=57600
pro.menu.cpu.8MHzatmega328.bootloader.low_fuses=0xFF pro.menu.cpu.8MHzatmega328.bootloader.low_fuses=0xFF
@ -496,6 +515,7 @@ pro.menu.cpu.8MHzatmega328.build.f_cpu=8000000L
pro.menu.cpu.16MHzatmega168=ATmega168 (5V, 16 MHz) pro.menu.cpu.16MHzatmega168=ATmega168 (5V, 16 MHz)
pro.menu.cpu.16MHzatmega168.upload.maximum_size=14336 pro.menu.cpu.16MHzatmega168.upload.maximum_size=14336
pro.menu.cpu.16MHzatmega168.upload.maximum_data_size=1024
pro.menu.cpu.16MHzatmega168.upload.speed=19200 pro.menu.cpu.16MHzatmega168.upload.speed=19200
pro.menu.cpu.16MHzatmega168.bootloader.low_fuses=0xff pro.menu.cpu.16MHzatmega168.bootloader.low_fuses=0xff
@ -511,6 +531,7 @@ pro.menu.cpu.16MHzatmega168.build.f_cpu=16000000L
pro.menu.cpu.8MHzatmega168=ATmega168 (3.3V, 8 MHz) pro.menu.cpu.8MHzatmega168=ATmega168 (3.3V, 8 MHz)
pro.menu.cpu.8MHzatmega168.upload.maximum_size=14336 pro.menu.cpu.8MHzatmega168.upload.maximum_size=14336
pro.menu.cpu.8MHzatmega168.upload.maximum_data_size=1024
pro.menu.cpu.8MHzatmega168.upload.speed=19200 pro.menu.cpu.8MHzatmega168.upload.speed=19200
pro.menu.cpu.8MHzatmega168.bootloader.low_fuses=0xc6 pro.menu.cpu.8MHzatmega168.bootloader.low_fuses=0xc6
@ -544,6 +565,7 @@ atmegang.build.variant=standard
atmegang.menu.cpu.atmega168=ATmega168 atmegang.menu.cpu.atmega168=ATmega168
atmegang.menu.cpu.atmega168.upload.maximum_size=14336 atmegang.menu.cpu.atmega168.upload.maximum_size=14336
atmegang.menu.cpu.atmega168.upload.maximum_data_size=1024
atmegang.menu.cpu.atmega168.bootloader.low_fuses=0xff atmegang.menu.cpu.atmega168.bootloader.low_fuses=0xff
atmegang.menu.cpu.atmega168.bootloader.high_fuses=0xdd atmegang.menu.cpu.atmega168.bootloader.high_fuses=0xdd

View File

@ -53,8 +53,10 @@ recipe.objcopy.eep.pattern="{compiler.path}{compiler.objcopy.cmd}" {compiler.obj
recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex"
## Compute size ## Compute size
recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.hex" recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf"
recipe.size.regex=Total\s+([0-9]+).* recipe.size.regex=^(?:\.text|\.data|\.bootloader)\s+([0-9]+).*
recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).*
recipe.size.regex.eeprom=^(?:\.eeprom)\s+([0-9]+).*
# AVR Uploader/Programmers tools # AVR Uploader/Programmers tools