low memory, floating point - sprintf

Status
Not open for further replies.

dons7777

Member
I've come across a situation where code hangs in sprintf (using %f). It was tricky to isolate the problem because it seemed to occur intermittingly.

The problem appears to be related to low dynamic memory (due to global variables) and use of floating point operations (emulated with Teensy 3.2)

Included is a small code example that demonstrates the issue.

Sprintf will hang after some number of floating point operations. I'm guessing that successive FP operations are in some way using up memory resources which eventually causes sprintf to hang.

I'm wondering if this could be a more general problem, in that libraries have memory requirements that result in elusive run time failures.
 

Attachments

  • z-sprintf-float.txt
    734 bytes · Views: 83
Code can be pasted directly and usably with the "#" CODE tag wrapper on the reply bar.

Is 'buf[51844];' this large on purpose to trigger the problem? Interesting 2 bytes larger and it fails on first use - does it ever hang if made ~32 bytes smaller?

What compile options are in use for 'optimize' and 'USB Type'? Would need to know for repro as behavior likely to change.

What values are printed on 'program storage' space and 'dynamic memory' RAM usage when compile completes to upload?

I added three BOLD lines below to the posted code - that should have the LED glowing - does the LED stay ON/OFF when you see it as hung?

Code:
// testing on Teensy 3.2  (no floating point unit)

// char   buf[51846];    //  hangs on first use of sprintf with float format
   char   buf[51844];    //  works initially, but eventually hangs in sprintf

int cnt = 0;
float x1 = 1.234;
[B]#define qBlink() {GPIOC_PTOR=32;} // BLINK LED_BUILTIN Pin 13
[/B]
void setup() {
[B]  pinMode(LED_BUILTIN, OUTPUT);[/B]
}

void loop() {
  cnt ++;
  delay(10);
  sprintf( buf, "BEGIN cnt=%6d  ...  ", cnt );
  Serial.print( buf );

[B]  qBlink();[/B]

  float tmp1 = x1 ;
  
//  x1 = tmp1;          //  didn't hang, up to 50,000 iterations
//  x1 = tmp1 + 0.96 ;  //  hangs after  ~  4317  iterations
//  x1 = tmp1 / 0.96 ;  //  hangs after  ~   237  iterations
    x1 = tmp1 * 0.96 ;  //  hangs after  ~   175  iterations

  sprintf( buf, "x1 = %10.3f ", x1 );
  
  Serial.print( buf );
  Serial.println( "   END" );
}
 
> Is 'buf[51844];' this large on purpose to trigger the problem?
>
Yes. Problem originally occurred in a much larger, complicated sketch.
After much trial & error, figured out simple code that would also cause it.

> does it ever hang if made ~32 bytes smaller?
>
Yes, seems to hang on first sprintf for buf[n] ... n for any value > 51844
I tried ~32 bytes smaller, no change

> What compile options are in use for 'optimize' and 'USB Type'?
>
Compiling sketch...
"/Users/drs/arduino-teensy-2018/Arduino-2.app/Contents/Java/hardware/teensy/../tools/arm/bin/arm-none-eabi-g++" -c -O2 -g -Wall -ffunction-sections -fdata-sections -nostdlib -MMD -fno-exceptions -felide-constructors -std=gnu++14 -fno-rtti -mthumb -mcpu=cortex-m4 -fsingle-precision-constant -D__MK20DX256__ -DTEENSYDUINO=141 -DARDUINO=10805 -DF_CPU=96000000 -DUSB_SERIAL -DLAYOUT_US_ENGLISH "-I/Users/drs/arduino-teensy-2018/Arduino-2.app/Contents/Java/hardware/teensy/avr/cores/teensy3" "/var/folders/bk/w7lfqtqs5h7_sn1d56_2s70c0000gn/T/arduino_build_78660/sketch/sketch_18apr10a.ino.cpp" -o "/var/folders/bk/w7lfqtqs5h7_sn1d56_2s70c0000gn/T/arduino_build_78660/sketch/sketch_18apr10a.ino.cpp.o"

> What values are printed on 'program storage' space and
> 'dynamic memory' RAM usage when compile completes to upload?
>
Sketch uses 31484 bytes (12%) of program storage space.
Maximum is 262144 bytes.
Global variables use 56772 bytes (86%) of dynamic memory,
leaving 8764 bytes for local variables.
Maximum is 65536 bytes.

> I added three BOLD lines below to the posted code
> - that should have the LED glowing
> - does the LED stay ON/OFF when you see it as hung?
>
LED stays on before and after code hangs
 
buf[51844] ... Makes sense ... 14% RAM left seems like it should work.

With a delay(10) the LED should be dimmer than always on - if the intensity is not changing then I suspect it is not HUNG - but running 'silent' - trashed the USB stack - not any better but changes the details somewhat.

Make this change in setup to show FULL on:
Code:
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWriteFast(LED_BUILTIN, HIGH);
  while( !Serial );
}

Perhaps add this to loop() - that will slow the test - but make clear that loop() is cycling or not:
Code:
  if ( !(millis()%1000) ) { delay(100);   qBlink(); }
 
Sketch in post #2 with buf[51846] seems to work with optimization Fast up to iteration 175, but hangs immediately for Faster or Fastest
Works with 51844 works up to 175 iterations -- hangs even with Fast
(sprintf() doesn't support float conversions with Optimization Smallest)
Seems to run with buf[50000]

Strange???

I think sprintf() uses malloc() so could be a memory leak or stack-heap collision. i'm still looking for Teensy source files for sprintf() ...
 
Last edited:
I put delay(100) before & after digitalWrite(ledPin, HIGH) and digitalWrite(ledPin, LOW) after the sprintf.

The LED blinks during each iteration, then stays on solid after the hang on iteration 175.

Wouldn't that indicate that the Teensy is HUNG rather than just trashed USB stack?


Code:
// testing on Teensy 3.2  (no floating point unit)

// char   buf[51846];    //  hangs on first use of sprintf with float format
// char   buf[51844];    //  works initially, but eventually hangs in sprintf
   char   buf[51844];

int cnt = 0;
float x1 = 1.234;
const int ledPin = 13;

void setup() {
  pinMode(ledPin, OUTPUT);
}

void loop() {
  cnt ++;
  
  delay(100);
  digitalWrite(ledPin, HIGH);
  delay(100);
  
  sprintf( buf, "BEGIN cnt=%6d  ...  ", cnt );
  
  Serial.print( buf );

  float tmp1 = x1 ;
  
//  x1 = tmp1;          //  doesn't seem to hang
//  x1 = tmp1 + 0.96 ;  //  hangs after  ~  4317  iterations
//  x1 = tmp1 / 0.96 ;  //  hangs after  ~   237  iterations
    x1 = tmp1 * 0.96 ;  //  hangs after  ~   175  iterations

  sprintf( buf, "x1 = %10.3f ", x1 );

  digitalWrite(ledPin, LOW);
  
  Serial.print( buf );
  Serial.println( "   END" );
}
 
I put delay(100) before & after digitalWrite(ledPin, HIGH) and digitalWrite(ledPin, LOW) after the sprintf.

The LED blinks during each iteration, then stays on solid after the hang on iteration 175.

Wouldn't that indicate that the Teensy is HUNG rather than just trashed USB stack?

I think the Teensy is halting because of a stack-heap collision. You need to use a smaller buf[] size, say 50000
 
What is also strange is that it doesn't seem to hang if the floating point operations are removed.

Also, the hang occurs much sooner with FP multiples or divides, rather than just addition.

Maybe the memory issue is in the floating point emulation and sprintf does FP operations in an particular way that triggers the hang.
 
> I think the Teensy is halting because of a stack-heap collision.
> You need to use a smaller buf[] size, say 50000

Yes, that does to get around the problem.
But the question remains - what is the safe limit for remaining dynamic memory.

What I did to get around the problem is just replace sprintf with a simple float-to string function.
 
Status
Not open for further replies.
Back
Top