GetTextExtentPoint32 is really slow on Windows Mobile, any alternative?
I wrote a simple demo below to discover why GetTextExtentPoint32 is slow,
Code:
void CSmartGetTextExtentDlg::OnBnClickedButton1()
{
// TODO: Add your control notification handler code here
CDC* dc = GetDC();
HDC hdc = dc->GetSafeHdc();
printf("begin GetTextExtent test\n");
string text1("Initialize the shell activate info structure");
SIZE size;
UINT64 startTime = getTicks();
::GetTextExtentPoint32(hdc, (LPCTSTR)(text1.c_str()), text1.size(), &size);
UINT64 endTime = getTicks();
UINT64 duration = endTime - startTime;
printf("str1: %d ms\n", duration);
string text2("Initialize the shell activate info structure");
startTime = getTicks();
::GetTextExtentPoint32(hdc, (LPCTSTR)(text2.c_str()), text2.size(), &size);
endTime = getTicks();
duration = endTime - startTime;
printf("str2: %d ms\n", duration);
printf("end GetTextExtent test\n\n");
ReleaseDC(dc);
}
The result was really confusing.
In first run, the 2 resulting duration were all around 300~400ms, even if they were same strings.
Then I clicked button to trigger test again, the time cost was obviously decreased to almost 0ms.
I restarted demo, the result was 0~1ms every time.
Then I reboot my device (not simulator), ran test twice or more like above, the first run was still slow, and became faster after that.
I guessed the system cached something I didn't figure out, but the confusing thing was that why it was slow even if they're 2 same strings in first run.
Any idea about this weird thing and any alternative?
thx in advance.
Re: GetTextExtentPoint32 is really slow on Windows Mobile, any alternative?
I have used GetTextExtentPoint32() on a desktop PC, and it is slow.
So, now, I use an alternative solution, which is to load the table of widths of the characters and compute the size of my string by adding the widths of characters.
I load the widths with something like:
Code:
int far font_width[256 - 32];
struct _ABC font_abcwidth[256 - 32];
...
GetCharWidth(hdc_mem, 32, 255, font_width);
if (GetCharABCWidths(hdc_mem, 32, 255, font_abcwidth) == 0) {
// It has failed, maybe not a true type font
for (i = 0; i < 255 - 32; i++) {
font_abcwidth[i].abcA = 0;
font_abcwidth[i].abcB = (UINT) (font_width[i]);
font_abcwidth[i].abcC = 0;
}
}
Re: GetTextExtentPoint32 is really slow on Windows Mobile, any alternative?
The GetTicks isn't an accurate measuring method. It has a precision of about 15 msec. So, if you measure one single call you normally would get 0 or 15/16 msec time difference.
The GetTextExtentPoint32 is a messaging method, i. e. it puts an request to the message queue where it was handled delayed depending on the message traffic. Like all GUI transactions it is relatively slow cause a user hardly won't recocnize waiting times less than a second.
If you want to make a better test for the GetTextExtentPoint32 you should read phrases from a text file with - say - 1000 lines or more and call GetTextExtentPoint32 in a loop. Then the measured time will much better reflect the real times.
Note, any performance tests must be made in release mode. You can't judge results which are made in debug mode.
Re: GetTextExtentPoint32 is really slow on Windows Mobile, any alternative?
There's no reason for this function to be as slow as you're indicating. It does hide a LOT of processing, so it does take "some" time of course.
But it's not "slow".
Something like DrawText() with multiline/word wrap does lots of calls to this (or similar) functions. Drawing a listcontrol equally does a lot of calls to this function to shorten text by using ellipsis if you have small columns.
Even a slow mobile device should be able to handle a couple hundred calls per second, a modern desktop should be able to handle a couple tens to hundred thousand calls per second.
Quote:
Originally Posted by
olivthill2
I have used GetTextExtentPoint32() on a desktop PC, and it is slow.
So, now, I use an alternative solution, which is to load the table of widths of the characters and compute the size of my string by adding the widths of characters.
This MAY work, but it won't always work.
- Some fonts/devices use kerning. This will mess up your assumption.
- There may be extra intercharacter spacing (SetTextCharacterExtra) active.
- Justification may be active
- Your calculations may be off for bold and/or italic fonts.
Quote:
Originally Posted by
itsmeandnobodyelse
The GetTextExtentPoint32 is a messaging method, i. e. it puts an request to the message queue where it was handled delayed depending on the message traffic. Like all GUI transactions it is relatively slow cause a user hardly won't recocnize waiting times less than a second.
UH ? Say what ?
This is just a normal function like so many other, it doesn't do any messages at all.
There's a lot of reasons why a first time would be slower...
- Needing to load/prepare the font for usage,
- Possibly needing to load extra dll's to do text painting
And there's more than enough reasons why it would be "occasionally" slower, such as requi
Although i can't really think of a good reason why that would impact both of the first 2 and not the subsequent ones
Re: GetTextExtentPoint32 is really slow on Windows Mobile, any alternative?
@olivthill2
Caching a table of widths of characters didn't include inter-spacing and others like what @OReubens said. But it would be a simple way and probably fit for many cases.
You all reminded me that I should NOT only run performance tests under *debug* mode.
I just ran test under Release mode, the result was a little bit faster though. Although I didn't quite trust my testing result, but it's the fact that GetTextExtentPoint32 is slow, the time consumption by calling GetTextExtentPoint32 took almost half of total time in my case. And I've also found that some other posts mentioned that.
@OReubens
I don't think it's *occasionally* slower. You know, it's always slow in first run, and go much more fast after that. The root reason I believe is that how system do cache-like stuff, which I have no idea.
btw, I used QueryPerformanceFrequency to implement my own getTick instead of system GetTickCount API.
Re: GetTextExtentPoint32 is really slow on Windows Mobile, any alternative?
ok, now we're getting there...
If you do QueryPerformanceFrequency() type timing, then you need to:
- Set An affinity to your testing thread to a single processor.
- Either increase thread priority, or increase your chances that your test code won't be interrupted, the easiest is putting a Sleep(100); call before your test start. This should normally force a yield, and next time your thread gets time, you'll have a full timeslice to play with, if your test isn't longer than a timeslice, you should be safe.
- You need to allow a single run through the entire test code. (more on this)
- Since you're timing very short code sequences, you need to deduct the time it takes to actually make the time calls. Do a start = getTick(), end=getTick(); and end-start will give you the overhead of the timing itself.
- never time test debug builds, never test release builds in debug mode. Both of these will sometimes give totally whacky and unreliable results.
- to prevent the compiler from reorganizing too much code to lie into the 2 time calls, you need to make the start and end variables volatile. This will act as a 'gate' so the compiler can't move code around the calls.
The single run thing:
QueryPerformance type timing, counts actual CPU cycles, but when you get into this order of cyclecounting, then small details about how the system works will have big impact on your timing, especially the first time through.
- The code you're testing may be on a page that isn't in memory yet. This means the page needs to be loaded from disk. This alone will just totally destroy any type of reasonable measurement.
- Your CPU cache could just have been trashed by what's happening before the test, upsetting any reasonable assumptions. You're doing a sprintf() just before the test, which is pretty much as bad as can get.
Even the creation of the CString can upset timing because of CPU cache. Remember, what you're wanting to do here is to measure the textExtent call, but what you're doing before the test start does in fact have an impact on that, and using a 'cycle counting' appproach means you HAVE to exclude as much of the variable as you can.
Even though it doesn't look like it, the compiler may be throwing some stuff around and this will upset the data.
The easy way to do measurement is to just do a couple hundred/thousand calls of a particular function and just measure with GetTickCount(), you typically want to have enough calls so you'll have a 5-10second period of testing. The results you then get will give you a good average of the speed you're going to get in real case scenario's.
clock cycle counting using QueryPerformance...(), can time very short intervals accurately, but, you also need to account for everything that might be adding time to your actual test-code. It's very twitchy and takes quite a bit of planning to get numbers that actually make sense. And with this kind of short intervals, even small bits of extra code or OS/CPU side effects like caching, on demand loading of data/code pages can have a really big impact.
Re: GetTextExtentPoint32 is really slow on Windows Mobile, any alternative?
@OReubens
thx, I didn't realize how performance test is supposed to be so sophisticated. I'll try further test.
Re: GetTextExtentPoint32 is really slow on Windows Mobile, any alternative?
Quote:
Originally Posted by
LifeIsSuffering
You all reminded me that I should NOT only run performance tests under *debug* mode.
You should never run performance test under debug mode, (unless you're responsible for the underlying C++ and C runtime library for the next version of VC++, and have it as a goal to get debug mode programs to run faster).
Secondly, you must specify _SECURE_SCL=0 in your preprocessor settings for release mode. The reason is that STL containers and strings still use iterator checking for release mode if that setting is not specified. Once you do that, then retime your tests.
Regards,
Paul McKenzie