Sonic and Sega Retro Message Board: Programming tips & tricks - Sonic and Sega Retro Message Board

Jump to content

Hey there, Guest!  (Log In · Register) Help
Page 1 of 1
    Locked
    Locked Forum

Programming tips & tricks

#1 User is offline GerbilSoft 

Posted 24 July 2014 - 12:06 PM

  • RickRotate'd.
  • Posts: 2846
  • Joined: 11-January 03
  • Gender:Male
  • Location:USA
  • Project:Gens/GS
  • Wiki edits:5,000 + one spin
Occasionally I find some useful tricks when programming stuff that can improve performance or otherwise enhance the resulting software. This thread will be used to collect assorted tips and tricks, and you can post your own interesting stuff here too.

Today's tip: MSVC's cout is ridiculously slow. It turns out this is because MSVC doesn't normally buffer cout (and probably cerr) by default.

Solution: Add this to the beginning of your program:
if (setvbuf(stdout, 0, _IOLBF, 4096) != 0) {
	abort();
}
if (setvbuf(stderr, 0, _IOLBF, 4096) != 0) {
	abort();
}


This sets a 4K line buffer for both stdout and stderr. I ran the test program listed at the below MS Connect page, and found that on MSVC 2010, this improves printf() performance by around 1x-1.5x, and cout performance by over 30x. (MSVC 2013 performance with setvbuf() was slightly faster than MSVC 2010, but interestingly it was slower than 2010 if setvbuf() wasn't used.)

(Reference: https://connect.micr...ug-in-c-library )

[NOTE: The referenced page also has a tip for using cout.pubsetbuf(), but on MSVC 2013 at least, if the buffer isn't flushed using endl, MSVCP120 may overflow the buffer, resulting in a crash. It doesn't improve performance that much compared to setvbuf() anyway, so don't bother using it.]

I haven't tested mingw gcc or Linux gcc yet, but I would assume both of those properly buffer stdout and cout. (...actually, considering that's a property of the C library, it'd more appropriately be MSVCRT [which doesn't buffer stdout] and glibc [which might?].)

EDIT: MSVC doesn't actually support line buffering. Enabling line buffering will actually enable full buffering, which may be problematic since printf() on MSVC 2010 doesn't seem to flush the buffer after a newline. endl does flush the buffer. If you're using printf, you can flush the buffer manually using fflush(stdout), but that isn't optimal.
This post has been edited by GerbilSoft: 24 July 2014 - 03:39 PM
Reason for edit: +flush warning

#2 User is offline MainMemory 

Posted 24 July 2014 - 01:21 PM

  • Every day's the same old thing... Same place, different day...
  • Posts: 4247
  • Joined: 14-August 09
  • Gender:Not Telling
  • Project:SonLVL
  • Wiki edits:1,339
In C++, you can get the number of elements in an array by using:
template <typename T, size_t N>
inline size_t LengthOfArray(const T(&)[N])
{
	return N;
}

Similarly, the total size of an array can be retrieved with:
template <typename T, size_t N>
inline size_t SizeOfArray(const T(&)[N])
{
	return N * sizeof(T);
}


#3 User is offline Hendricks 266 

Posted 24 July 2014 - 07:59 PM

  • Posts: 362
  • Joined: 01-June 05
  • Gender:Male
  • Location:United States
  • Wiki edits:58

View PostMainMemory, on 24 July 2014 - 01:21 PM, said:

In C++, you can get the number of elements in an array by using:
template <typename T, size_t N>
inline size_t LengthOfArray(const T(&)[N])
{
	return N;
}


Is there any significant difference between this and sizeof(array)/sizeof(array[0])?

#include <stdio.h>

template <typename T, size_t N>
inline size_t LengthOfArray(const T(&)[N])
{
	return N;
}

size_t pointer_sizeof(int array[])
{
    return sizeof(array)/sizeof(array[0]);
}
#if 0
// doesn't compile: no matching function for call to 'LengthOfArray(int*&)'
size_t pointer_template(int array[])
{
    return LengthOfArray(array);
}
#endif

int main(void)
{
    int array[1000];

    printf("%u\n", sizeof(array)/sizeof(array[0]));
    printf("%u\n", LengthOfArray(array));
    printf("%u\n", pointer_sizeof(array));
    // printf("%zu\n", pointer_template(array));

    return 0;
}


gives:

1000
1000
1

I suppose it has the benefit of type checking, but sizeof works in straight C too.
This post has been edited by Hendricks 266: 24 July 2014 - 08:04 PM

#4 User is offline MainMemory 

Posted 24 July 2014 - 11:41 PM

  • Every day's the same old thing... Same place, different day...
  • Posts: 4247
  • Joined: 14-August 09
  • Gender:Not Telling
  • Project:SonLVL
  • Wiki edits:1,339
The only difference is type checking, it prevents accidentally converting an array to a pointer as in your pointer_sizeof function.

#5 User is offline Billy 

Posted 25 July 2014 - 02:08 AM

  • RIP Oderus Urungus
  • Posts: 1817
  • Joined: 24-June 05
  • Gender:Male
  • Location:Colorado, USA
  • Project:retrooftheweek.net - Give it a visit and tell me what you think!
  • Wiki edits:15
If you're using C++11, look into shared_ptr. It can very verbose in terms of code, but pretty handy in the right situation.

Making a game and you need to detect collisions between a lot of objects? Use quadtrees.

A better random number generator for C++: here.

Here's one from me: Line of sight testing in a 2D tile based game. (Let me know if there's any errors with this one, please)

#6 User is offline MainMemory 

Posted 25 July 2014 - 01:26 PM

  • Every day's the same old thing... Same place, different day...
  • Posts: 4247
  • Joined: 14-August 09
  • Gender:Not Telling
  • Project:SonLVL
  • Wiki edits:1,339
I use shared_ptr to manage a block of data allocated by a class' initializer in the SADX Mod Loader, so it gets deleted automatically when the last instance of the object does. It's not ideal, since other code could hold pointers into the block of data when the object is deleted, but I think it's better than requiring the client to manually delete the data.

#7 User is offline GerbilSoft 

Posted 04 August 2014 - 11:24 AM

  • RickRotate'd.
  • Posts: 2846
  • Joined: 11-January 03
  • Gender:Male
  • Location:USA
  • Project:Gens/GS
  • Wiki edits:5,000 + one spin
Today's tip: Don't pass std::string (or any other large object) by value.

int someFunction(std::string x)
{
	// blah
}


If your function doesn't modify the string, then it's better to pass it by const reference. gcc uses copy-on-write strings, so it has to increment a reference counter every time you pass a string by value. MSVC, on the other hand, uses "short strings", which requires copying at least 28 bytes (32-bit) or 40 bytes (64-bit) every time you pass a string by value. This isn't including the string data itself, which is either stored within the string object if it's 15 bytes or less, or allocated separately on the heap if it's larger than 16 bytes.

Do this instead:

int someFunction(const std::string &x)
{
	// blah
}


This is effectively passing a const pointer that works the same way as a regular object.

Supposedly C++ 2011 eliminates the need for passing by const reference by using "move semantics", but it hasn't been adopted much outside of e.g. libstdc++ and boost. I'd recommend using const reference anyway, since it also prevents accidental string overwrites.

Page 1 of 1
    Locked
    Locked Forum

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users