Platformio - Remaining memory as percentages

This is probably a super simple, basic question and for that, forgive me.

I use Platformio with VSCode and the T4.1 - On building the code it shows the memory used such as:

teensy_size: Memory Usage on Teensy 4.1:
teensy_size: FLASH: code:45552, data:7412, headers:8472 free for files:8065028
teensy_size: RAM1: variables:21184, code:42880, padding:22656 free for local variables:437568
teensy_size: RAM2: variables:12384 free for malloc/new:511904

I don't really have an instinctual eye (especially if it's a quick glance) for seeing the above and working out quite how much memory I am using/have remaining.

Is there a way inside VSCode / Platformio (or perhaps something I can add/mod) that will instead show the info as percentages remaining?
 
teensy size: code:45552, data:7412, headers:8472 free for files:8065028
teensy_size: RAM1: variables:21184, code:42880, padding:22656 free for local variables:437568
teensy_size: RAM2: variables:12384 free for malloc/new:511904

how much memory I am using/have remaining?

The info above is showing you how much is used and how much is free (not used) in each section:

Teensy 4.1 total FLASH is 8MB = 8*1024*1024 = 8388608 bytes. You have 8065028 free, so % used is (total - free)/total = (8388608 - 8065028)/8388608 = 3.5% used

RAM1 and RAM2 are both 512K (512*1024 = 524288), so you can do the same math on those. You have used very little so far.
 
Appreciate that!

It is, however, the kind of at a glance maths my tired 'I'm not sleeping until I fix this' eyes don't like to do. All those long numbers blend into one :D

Is there a way to modify 'whatever' is writing that piece of information to the terminal, to simple tack on the percentages to the end?
 
It is called after build on the ELF file: recipe.hooks.postbuild.3.pattern="{compiler.path}teensy_size" "{build.path}/{build.project_name}.elf"

It parses the records for the info it gets.

The linked "C" source can be edited to a local copy as desired.
 
So I changed the teensy_size code to:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>

#include "minimal_elf.h"

void die(const char *format, ...) __attribute__ ((format (printf, 1, 2)));

unsigned char *filedata = NULL;
FILE *fp = NULL;


const char * model_name(int num)
{
	switch (num) {
		case 0x19: return "Teensy 1.0";
		case 0x1A: return "Teensy++ 1.0";
		case 0x1B: return "Teensy 2.0";
		case 0x1C: return "Teensy++ 2.0";
		case 0x1D: return "Teensy 3.0";
		case 0x1E: return "Teensy 3.1";
		case 0x1F: return "Teensy 3.5";
		case 0x20: return "Teensy LC";
		case 0x21: return "Teensy 3.2";
		case 0x22: return "Teensy 3.6";
		case 0x23: return "Teensy 4-Beta1";
		case 0x24: return "Teensy 4.0";
		case 0x25: return "Teensy 4.1";
		case 0x26: return "Teensy MicroMod";
	}
	return "Teensy";
}

uint32_t flash_size(int model)
{
	if (model == 0x24) return 2031616;  // Teensy 4.0
	if (model == 0x25) return 8126464;  // Teensy 4.1
	if (model == 0x26) return 16515072; // MicroMod
	return 0;
}


int main(int argc, char **argv)
{
	int retval = 0;
	if (argc < 2) die("usage: teensy_size <file.elf>\n");
	const char *filename = argv[1];
	fp = fopen(filename, "rb");
	if (!fp) die("Unable to open for reading %s\n", filename);
	fseek(fp, 0, SEEK_END);
	size_t filesize = ftell(fp);
	filedata = malloc(filesize);
	if (!filedata) die("unable to allocate %ld bytes\n", (long)filesize);
	rewind(fp);
	if (fread(filedata, 1, filesize, fp) != filesize)  die("Unable to read %s\n", filename);
	fclose(fp);
	fp = NULL;
	if (parse_elf(filedata) != 0) die("Unable to parse %s\n", filename);


	int model = elf_teensy_model_id(filedata);
	if (!model) die("Can't determine Teensy model from %s\n", filename);

	//print_elf_info();
	//printf("Teensy Model is %02X (%s)\n", model, model_name(model));

	if (model == 0x24 || model == 0x25 || model == 0x26) {

		uint32_t text_headers = elf_section_size(".text.headers");
		uint32_t text_code = elf_section_size(".text.code");
		uint32_t text_progmem = elf_section_size(".text.progmem");
		uint32_t text_itcm = elf_section_size(".text.itcm");
		uint32_t arm_exidx = elf_section_size(".ARM.exidx");
		uint32_t data = elf_section_size(".data");
		uint32_t bss = elf_section_size(".bss");
		uint32_t bss_dma = elf_section_size(".bss.dma");
		uint32_t text_csf = elf_section_size(".text.csf");

		uint32_t flash_total = text_headers + text_code + text_progmem
			+ text_itcm + arm_exidx + data + text_csf;
		uint32_t flash_headers = text_headers + text_csf;
		uint32_t flash_code = text_code + text_itcm + arm_exidx;
		uint32_t flash_data = text_progmem + data;

		uint32_t itcm = text_itcm + arm_exidx;
		uint32_t itcm_blocks = (itcm + 0x7FFF) >> 15;
		uint32_t itcm_total = itcm_blocks * 32768;
		uint32_t itcm_padding = itcm_total - itcm;
		uint32_t dtcm = data + bss;
		uint32_t ram2 = bss_dma;

		int32_t free_flash = (int32_t)flash_size(model) - (int32_t)flash_total;
		int32_t free_for_local = 512*1024 - (int32_t)itcm_total - (int32_t)dtcm;
		int32_t free_for_malloc = (int32_t)512*1024 - (int32_t)ram2;
		
		float percent_flash_remaining = (float)(flash_size(model) - free_flash) / flash_size(model);
		float percent_ram1_remaining = (float)((512*1024) - free_for_local) / (512*1024);
		float percent_ram2_remaining = (float)((512*1024) - free_for_malloc) / (512*1024);

		const char *prefix = "teensy_size: ";
		if ((free_flash < 0) || (free_for_local <= 0) || (free_for_malloc < 0)) retval = -1;

		fprintf(stderr,
			"%sMemory Usage on %s:\n", prefix, model_name(model));
		fprintf(stderr,
			"%s FLASH: code: %u  |  data: %u  |  headers: %u  |  free for files: %d\n",
			(free_flash < 0) ? "" : prefix,
			flash_code, flash_data, flash_headers, free_flash);
		fprintf(stderr,
			"%s  RAM1: variables: %u  |  code: %u  |  padding: %u  |  free for local variables: %d\n",
			(free_for_local <= 0) ? "" : prefix,
			dtcm, itcm, itcm_padding, free_for_local);
		fprintf(stderr,
			"%s  RAM2: variables: %u  |  free for malloc/new: %d\n",
			(free_for_malloc < 0) ? "" : prefix,
			ram2, free_for_malloc);
		fprintf(stderr,
			"\nFLASH used: %.5f %%\n RAM1 used: %.5f %%\n RAM2 used: %.5f %%\n", percent_flash_remaining, percent_ram1_remaining, percent_ram2_remaining);

		if (model == 0x25) {
			uint32_t bss_extram = elf_section_size(".bss.extram");
			if (bss_extram > 0) {
				fprintf(stderr,
					"%s EXTRAM: variables:%u\n", prefix, bss_extram);
			}
		}
		if (retval != 0) {
			fprintf(stderr,"Error program exceeds memory space\n");
		}
		fflush(stderr);
	}

	free(filedata);
	return retval;
}



void die(const char *format, ...)
{
	va_list args;
	va_start(args, format);
	fprintf(stderr, "teensy_size: ");
	vfprintf(stderr, format, args);
	va_end(args);
	if (fp) fclose(fp);
	if (filedata) free(filedata);
	exit(1);
}

And now I get the output:

Code:
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:  FLASH: code: 45552  |  data: 7412  |  headers: 8472  |  free for files: 8065028
teensy_size:   RAM1: variables: 21184  |  code: 42880  |  padding: 22656  |  free for local variables: 437568
teensy_size:   RAM2: variables: 12384  |  free for malloc/new: 511904

FLASH used: 0.00756 %
 RAM1 used: 0.16541 %
 RAM2 used: 0.02362 %

(Which for me, is a little easier on the eyes too)

Do those percentages check out? Is it accurate?
 
Last edited:
Code:
uint32_t flash_size(int model)
{
	if (model == 0x24) return 2031616;  // Teensy 4.0
	if (model == 0x25) return 8126464;  // Teensy 4.1
	if (model == 0x26) return 16515072; // MicroMod
	return 0;
}

Seems to be a slightly different number than what was originally mentioned.

Here we go then:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>

#include "minimal_elf.h"

void die(const char *format, ...) __attribute__ ((format (printf, 1, 2)));

unsigned char *filedata = NULL;
FILE *fp = NULL;


const char * model_name(int num)
{
	switch (num) {
		case 0x19: return "Teensy 1.0";
		case 0x1A: return "Teensy++ 1.0";
		case 0x1B: return "Teensy 2.0";
		case 0x1C: return "Teensy++ 2.0";
		case 0x1D: return "Teensy 3.0";
		case 0x1E: return "Teensy 3.1";
		case 0x1F: return "Teensy 3.5";
		case 0x20: return "Teensy LC";
		case 0x21: return "Teensy 3.2";
		case 0x22: return "Teensy 3.6";
		case 0x23: return "Teensy 4-Beta1";
		case 0x24: return "Teensy 4.0";
		case 0x25: return "Teensy 4.1";
		case 0x26: return "Teensy MicroMod";
	}
	return "Teensy";
}

uint32_t flash_size(int model)
{
	if (model == 0x24) return 2031616;  // Teensy 4.0
	if (model == 0x25) return 8126464;  // Teensy 4.1
	if (model == 0x26) return 16515072; // MicroMod
	return 0;
}


int main(int argc, char **argv)
{
	int retval = 0;
	if (argc < 2) die("usage: teensy_size <file.elf>\n");
	const char *filename = argv[1];
	fp = fopen(filename, "rb");
	if (!fp) die("Unable to open for reading %s\n", filename);
	fseek(fp, 0, SEEK_END);
	size_t filesize = ftell(fp);
	filedata = malloc(filesize);
	if (!filedata) die("unable to allocate %ld bytes\n", (long)filesize);
	rewind(fp);
	if (fread(filedata, 1, filesize, fp) != filesize)  die("Unable to read %s\n", filename);
	fclose(fp);
	fp = NULL;
	if (parse_elf(filedata) != 0) die("Unable to parse %s\n", filename);


	int model = elf_teensy_model_id(filedata);
	if (!model) die("Can't determine Teensy model from %s\n", filename);

	//print_elf_info();
	//printf("Teensy Model is %02X (%s)\n", model, model_name(model));

	if (model == 0x24 || model == 0x25 || model == 0x26) {

		uint32_t text_headers = elf_section_size(".text.headers");
		uint32_t text_code = elf_section_size(".text.code");
		uint32_t text_progmem = elf_section_size(".text.progmem");
		uint32_t text_itcm = elf_section_size(".text.itcm");
		uint32_t arm_exidx = elf_section_size(".ARM.exidx");
		uint32_t data = elf_section_size(".data");
		uint32_t bss = elf_section_size(".bss");
		uint32_t bss_dma = elf_section_size(".bss.dma");
		uint32_t text_csf = elf_section_size(".text.csf");

		uint32_t flash_total = text_headers + text_code + text_progmem
			+ text_itcm + arm_exidx + data + text_csf;
		uint32_t flash_headers = text_headers + text_csf;
		uint32_t flash_code = text_code + text_itcm + arm_exidx;
		uint32_t flash_data = text_progmem + data;

		uint32_t itcm = text_itcm + arm_exidx;
		uint32_t itcm_blocks = (itcm + 0x7FFF) >> 15;
		uint32_t itcm_total = itcm_blocks * 32768;
		uint32_t itcm_padding = itcm_total - itcm;
		uint32_t dtcm = data + bss;
		uint32_t ram2 = bss_dma;

		int32_t free_flash = (int32_t)flash_size(model) - (int32_t)flash_total;
		int32_t free_for_local = 512*1024 - (int32_t)itcm_total - (int32_t)dtcm;
		int32_t free_for_malloc = (int32_t)512*1024 - (int32_t)ram2;
		
		float percent_flash_remaining = ((float)(flash_size(model) - free_flash) / flash_size(model)) * 100.f;
		float percent_ram1_remaining = ((float)((512*1024) - free_for_local) / (512*1024)) * 100.f;
		float percent_ram2_remaining = ((float)((512*1024) - free_for_malloc) / (512*1024)) * 100.f;

		const char *prefix = "teensy_size: ";
		if ((free_flash < 0) || (free_for_local <= 0) || (free_for_malloc < 0)) retval = -1;

		fprintf(stderr,
			"%sMemory Usage on %s:\n", prefix, model_name(model));
		fprintf(stderr,
			"%s FLASH: code: %u  |  data: %u  |  headers: %u  |  free for files: %d\n",
			(free_flash < 0) ? "" : prefix,
			flash_code, flash_data, flash_headers, free_flash);
		fprintf(stderr,
			"%s  RAM1: variables: %u  |  code: %u  |  padding: %u  |  free for local variables: %d\n",
			(free_for_local <= 0) ? "" : prefix,
			dtcm, itcm, itcm_padding, free_for_local);
		fprintf(stderr,
			"%s  RAM2: variables: %u  |  free for malloc/new: %d\n",
			(free_for_malloc < 0) ? "" : prefix,
			ram2, free_for_malloc);
		fprintf(stderr,
			"\nFLASH used: %.2f %%\n RAM1 used: %.2f %%\n RAM2 used: %.2f %%\n", percent_flash_remaining, percent_ram1_remaining, percent_ram2_remaining);

		if (model == 0x25) {
			uint32_t bss_extram = elf_section_size(".bss.extram");
			if (bss_extram > 0) {
				fprintf(stderr,
					"%s EXTRAM: variables:%u\n", prefix, bss_extram);
			}
		}
		if (retval != 0) {
			fprintf(stderr,"Error program exceeds memory space\n");
		}
		fflush(stderr);
	}

	free(filedata);
	return retval;
}



void die(const char *format, ...)
{
	va_list args;
	va_start(args, format);
	fprintf(stderr, "teensy_size: ");
	vfprintf(stderr, format, args);
	va_end(args);
	if (fp) fclose(fp);
	if (filedata) free(filedata);
	exit(1);
}

And as output:

Code:
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:  FLASH: code: 45552  |  data: 7412  |  headers: 8472  |  free for files: 8065028
teensy_size:   RAM1: variables: 21184  |  code: 42880  |  padding: 22656  |  free for local variables: 437568
teensy_size:   RAM2: variables: 12384  |  free for malloc/new: 511904

FLASH used: 0.76 %
 RAM1 used: 16.54 %
 RAM2 used: 2.36 %
 
Code:
uint32_t flash_size(int model)
{
	if (model == 0x24) return 2031616;  // Teensy 4.0
	if (model == 0x25) return 8126464;  // Teensy 4.1
	if (model == 0x26) return 16515072; // MicroMod
	return 0;
}

Seems to be a slightly different number than what was originally mentioned.

For T4.0 and T4.1, some of the upper flash is reserved for a recovery "blink" program. This reduces the flash available for user programs, so there is less than 2MB available on T4.0 and less than 8MB available on T4.1. The function name flash_size() is a little misleading in that respect. It returns "user available size" as opposed to "total size".

Your calculations look okay.
 
Okay, nice. In that case - job done! And as promised, I didn't sleep until it was fixed ;) It's past midnight here in the UK now, so off to bed.

Thank you both very much!
 
It is different than for prior Teensy - like this for T_3.6:
Code:
Sketch uses 46640 bytes (4%) of program storage space. Maximum is 1048576 bytes.
Global variables use 4680 bytes (1%) of dynamic memory, leaving 257464 bytes for local variables. Maximum is 262144 bytes.

Adding a percentage might be nice - and has all the needed data.

But the 1062 MCU in T_4.x's/T_MM has more complex memory issues that may need to be understood to resolve certain build issues:
Code:
FLASH: [B][U]code: 45552  |  data: 7412  |  headers: 8472 [/U][/B] |  free for files: 8065028
RAM1: [B][U]variables: 21184  |  code: 42880  |  padding: 22656  |[/U][/B]  free for local variables: 437568

Though perhaps adding 4 chars - in some fashion - would be worthy?
Code:
FLASH 1%: [B][U]code: 45552  |  data: 7412  |  headers: 8472 [/U][/B] |  free for files: 8065028
RAM1 17%: [B][U]variables: 21184  |  code: 42880  |  padding: 22656  |[/U][/B]  free for local variables: 437568
 
That is better than duplicating some text, yes!

Code:
teensy_size: Memory Usage on Teensy 4.1:
teensy_size:  FLASH (0.77 %): code: 45936  |  data: 7452  |  headers: 9072  |  free for files: 8064004
teensy_size:   RAM1 (16.54 %): variables: 21184  |  code: 43264  |  padding: 22272  |  free for local variables: 437568
teensy_size:   RAM2 (2.36 %): variables: 12384  |  free for malloc/new: 511904

Using:

Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>

#include "minimal_elf.h"

void die(const char *format, ...) __attribute__ ((format (printf, 1, 2)));

unsigned char *filedata = NULL;
FILE *fp = NULL;


const char * model_name(int num)
{
	switch (num) {
		case 0x19: return "Teensy 1.0";
		case 0x1A: return "Teensy++ 1.0";
		case 0x1B: return "Teensy 2.0";
		case 0x1C: return "Teensy++ 2.0";
		case 0x1D: return "Teensy 3.0";
		case 0x1E: return "Teensy 3.1";
		case 0x1F: return "Teensy 3.5";
		case 0x20: return "Teensy LC";
		case 0x21: return "Teensy 3.2";
		case 0x22: return "Teensy 3.6";
		case 0x23: return "Teensy 4-Beta1";
		case 0x24: return "Teensy 4.0";
		case 0x25: return "Teensy 4.1";
		case 0x26: return "Teensy MicroMod";
	}
	return "Teensy";
}

uint32_t flash_size(int model)
{
	if (model == 0x24) return 2031616;  // Teensy 4.0
	if (model == 0x25) return 8126464;  // Teensy 4.1
	if (model == 0x26) return 16515072; // MicroMod
	return 0;
}


int main(int argc, char **argv)
{
	int retval = 0;
	if (argc < 2) die("usage: teensy_size <file.elf>\n");
	const char *filename = argv[1];
	fp = fopen(filename, "rb");
	if (!fp) die("Unable to open for reading %s\n", filename);
	fseek(fp, 0, SEEK_END);
	size_t filesize = ftell(fp);
	filedata = malloc(filesize);
	if (!filedata) die("unable to allocate %ld bytes\n", (long)filesize);
	rewind(fp);
	if (fread(filedata, 1, filesize, fp) != filesize)  die("Unable to read %s\n", filename);
	fclose(fp);
	fp = NULL;
	if (parse_elf(filedata) != 0) die("Unable to parse %s\n", filename);


	int model = elf_teensy_model_id(filedata);
	if (!model) die("Can't determine Teensy model from %s\n", filename);

	//print_elf_info();
	//printf("Teensy Model is %02X (%s)\n", model, model_name(model));

	if (model == 0x24 || model == 0x25 || model == 0x26) {

		uint32_t text_headers = elf_section_size(".text.headers");
		uint32_t text_code = elf_section_size(".text.code");
		uint32_t text_progmem = elf_section_size(".text.progmem");
		uint32_t text_itcm = elf_section_size(".text.itcm");
		uint32_t arm_exidx = elf_section_size(".ARM.exidx");
		uint32_t data = elf_section_size(".data");
		uint32_t bss = elf_section_size(".bss");
		uint32_t bss_dma = elf_section_size(".bss.dma");
		uint32_t text_csf = elf_section_size(".text.csf");

		uint32_t flash_total = text_headers + text_code + text_progmem
			+ text_itcm + arm_exidx + data + text_csf;
		uint32_t flash_headers = text_headers + text_csf;
		uint32_t flash_code = text_code + text_itcm + arm_exidx;
		uint32_t flash_data = text_progmem + data;

		uint32_t itcm = text_itcm + arm_exidx;
		uint32_t itcm_blocks = (itcm + 0x7FFF) >> 15;
		uint32_t itcm_total = itcm_blocks * 32768;
		uint32_t itcm_padding = itcm_total - itcm;
		uint32_t dtcm = data + bss;
		uint32_t ram2 = bss_dma;

		int32_t free_flash = (int32_t)flash_size(model) - (int32_t)flash_total;
		int32_t free_for_local = 512*1024 - (int32_t)itcm_total - (int32_t)dtcm;
		int32_t free_for_malloc = (int32_t)512*1024 - (int32_t)ram2;
		
		float percent_flash_remaining = ((float)(flash_size(model) - free_flash) / flash_size(model)) * 100.f;
		float percent_ram1_remaining = ((float)((512*1024) - free_for_local) / (512*1024)) * 100.f;
		float percent_ram2_remaining = ((float)((512*1024) - free_for_malloc) / (512*1024)) * 100.f;

		const char *prefix = "teensy_size: ";
		if ((free_flash < 0) || (free_for_local <= 0) || (free_for_malloc < 0)) retval = -1;

		fprintf(stderr,
			"%sMemory Usage on %s:\n", prefix, model_name(model));
		fprintf(stderr,
			"%s FLASH (%.2f %%): code: %u  |  data: %u  |  headers: %u  |  free for files: %d\n",
			(free_flash < 0) ? "" : prefix, percent_flash_remaining, 
			flash_code, flash_data, flash_headers, free_flash);
		fprintf(stderr,
			"%s  RAM1 (%.2f %%): variables: %u  |  code: %u  |  padding: %u  |  free for local variables: %d\n",
			(free_for_local <= 0) ? "" : prefix, percent_ram1_remaining,
			dtcm, itcm, itcm_padding, free_for_local);
		fprintf(stderr,
			"%s  RAM2 (%.2f %%): variables: %u  |  free for malloc/new: %d\n",
			(free_for_malloc < 0) ? "" : prefix, percent_ram2_remaining,
			ram2, free_for_malloc);

		if (model == 0x25) {
			uint32_t bss_extram = elf_section_size(".bss.extram");
			if (bss_extram > 0) {
				fprintf(stderr,
					"%s EXTRAM: variables:%u\n", prefix, bss_extram);
			}
		}
		if (retval != 0) {
			fprintf(stderr,"Error program exceeds memory space\n");
		}
		fflush(stderr);
	}

	free(filedata);
	return retval;
}



void die(const char *format, ...)
{
	va_list args;
	va_start(args, format);
	fprintf(stderr, "teensy_size: ");
	vfprintf(stderr, format, args);
	va_end(args);
	if (fp) fclose(fp);
	if (filedata) free(filedata);
	exit(1);
}
 
Last edited:
Back
Top