Imgui: Considering use of stb_sprintf

Created on 25 Feb 2017  路  8Comments  路  Source: ocornut/imgui

Hello,

stb_sprintf is a good replacement for sprintf, snprintf, vsprintf, and vsnprintf.
The 2 main reasons are performances (see the benchmarks in the file), and having the exact same behaviour on every platform.

One remaining issue is the implementation of vsnprintf which doesn't return the standard value. Usually, people use vsnprintf(NULL, 0, ...) to estimate the required buffer size, and then use vsnprintf(buffer, size, ...) to convert. In the current implementation, vsnprintf(NULL, 0, ...) always returns 0 (instead of returning the number of bytes required).

For ImGui, using stb_sprintf.h would ensure having the same results on every platforms.

enhancement

Most helpful comment

I yet have to evaluate stb_printf but knowing the RAD guys I'm sure it is super efficient.

I guess we could make it optional for a start, e.g. add a imconfig.h option where the user would need to add:

#include <stb_sprintf.h>
#define IMGUI_USE_STB_SPRINTF

If the function signature are the same we can then use add some #ifdef+#define at the top of imgui.cpp?

#ifdef IMGUI_USE_STB_SPRINTF
#undef vsnprintf
#define vsnprintf stbsp_vsnprintf

?

All 8 comments

The current performances (as of Feb2017) are those :

PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC):
"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC)
"%24d" across all 32-bit ints (4.5x/4.2x faster)
"%x" across all 32-bit ints (4.5x/3.8x faster)
"%08x" across all 32-bit ints (4.3x/3.8x faster)
"%f" across e-10 to e+10 floats (7.3x/6.0x faster)
"%e" across e-10 to e+10 floats (8.1x/6.0x faster)
"%g" across e-10 to e+10 floats (10.0x/7.1x faster)
"%f" for values near e-300 (7.9x/6.5x faster)
"%f" for values near e+300 (10.0x/9.1x faster)
"%e" for values near e-300 (10.1x/7.0x faster)
"%e" for values near e+300 (9.2x/6.0x faster)
"%.320f" for values near e-300 (12.6x/11.2x faster)
"%a" for random values (8.6x/4.3x faster)
"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster)
"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster)
"%s%s%s" for 64 char strings (7.1x/7.3x faster)
"...512 char string..." ( 35.0x/32.5x faster!)

I'm guessing its missing debug checks or something? Seems strange how it could be so much faster yet still handle all of the same cases.

Try GCC 5.3, and I guess you even built code in debug mode. You must build both benchmarks in release mode (for the gcc you must use the -O2 flag, or result will be built in debug mode, therefore it will be slower). In other side are was benchmarks are showing that MinGW built apps are giving faster result than MSVC's.

The case of MinGW it has own independent runtime (reason of bigger size of binaries, especially if you will use -static-libgcc and -static-libstdc++) which allows you to build app even for Windows 95 (if you will don't use unsupported functions in it), and the minimal supported Windows version is dependent of that which WinAPI functions you are using.

In case of ImGui, the biggest stake is not the performance, but having the exact same behaviour on each platform.

I yet have to evaluate stb_printf but knowing the RAD guys I'm sure it is super efficient.

I guess we could make it optional for a start, e.g. add a imconfig.h option where the user would need to add:

#include <stb_sprintf.h>
#define IMGUI_USE_STB_SPRINTF

If the function signature are the same we can then use add some #ifdef+#define at the top of imgui.cpp?

#ifdef IMGUI_USE_STB_SPRINTF
#undef vsnprintf
#define vsnprintf stbsp_vsnprintf

?

Yes, the signatures are the same.
But keep in mind the function vsnprintf doesn't return the same values than the standard (for the moment) ; I checked the use in ImGui, and it doesn't seem to impact it.
(Here is the discussion about standard behaviour of vsnprintf : https://github.com/nothings/stb/issues/408)

@itamago @paniq

I have pushed this small change:

If you set #define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS in imconfig.h it will remove the implementation of ImFormatString/ImFormatStringV so you can implement them yourself.

I think this solves the issue described in this thread without having to bother with trying to match exact prototypes between, e.g. vsnprintf and stbsp_vsnprintf.

If you have time to check it out, could you let me know if it works for you, in particular with stbsp_vsnprintf ? And if you can paste in your implementation of ImFormatString/ImFormatStringV using the stb code it'll be great. Thanks!

Note that the only piece of code in dear imgui relying on passing a NULL first parameter is ImGuiTextBuffer::appendv() which is a general purpose "long string builder" used by clipboard logging (LogToClipboard function), and the Log demo. And the double sprintf call could probably be improved. I haven't looked at stb_printf but if we can change the ImFormatString/ImFormatStringV specs to make code like ImGuiTextBuffer::appendv more efficient it would be great.

(repost with fixed typos)
Everyone please note that I have renamed IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS to IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS for consistency.
I made it that IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS will error during build to facilitate fixing for the change:

#ifdef IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS                // Renamed in 1.74
#error Use IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
#endif

Also closing this topic as it's pretty much supported now, and there's even a helper IMGUI_USE_STB_SPRINTF that perform the wrapping automatically in imgui.h if used.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dowit picture dowit  路  3Comments

inflex picture inflex  路  3Comments

ghost picture ghost  路  3Comments

mnemode2 picture mnemode2  路  3Comments

SlNPacifist picture SlNPacifist  路  3Comments