Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mysterious performance degrade with Open GL + infinite loop

I'm working on an emulator as a side/fun project, but I'm having some performance issues and failing to figure out where they are coming from.

The application is mainly composed of a GLKView for display, and a separate thread with an infinite loop for the cpu emulation. Here's a sample with all the actual emulation code taken out that still displays the problem:

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    GLKView *glView = [[GLKView alloc] initWithFrame:self.view.bounds];
    glView.delegate = self;
    glView.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    [EAGLContext setCurrentContext:glView.context];
    [self.view addSubview:glView];
    glView.enableSetNeedsDisplay = NO;
    CADisplayLink* displayLink = [CADisplayLink displayLinkWithTarget:glView selector:@selector(display)];
    [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

     dispatch_get_main_queue(), ^{
        dispatch_async(dispatch_queue_create("yeah", DISPATCH_QUEUE_SERIAL), ^{
            CFTimeInterval lastTime = 0;
            CFTimeInterval time = 0;
            int instructions = 0;
            while(1) {
                // here be cpu emulation
                if (lastTime == 0) {
                    lastTime = CACurrentMediaTime();
                } else {
                    CFTimeInterval newTime = CACurrentMediaTime();
                    time += newTime - lastTime;
                    lastTime = newTime;
                }
                if (++instructions == 1000) {
                    printf("%f\n", 1/(time * 1000));
                    time = 0;
                    instructions = 0;
                }
            }
        });
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    // Here be graphics
}

@end

Like this, the infinite loops is basically just counting it's iterations and printing out it's frequency in MHz.

So, the problem is, when the app starts, the loop runs at about 9-15 MHz (on an iPhone6), and if I look at the GPU Report in Xcode's Debug Navigator, I can see that the CPU frame time is 0.2ms Then, after running for a couple of seconds, the loop drops to 1-5 MHz, and the CPU frame time increases to 0.6ms

If I disable the GLKView updates, then the loops never become slower

I also tried using different threading API's (gdc, NSThread, pthread), but that doesn't seem to have any impact

My question is, am I doing something wrong somewhere? Is it just a case of the GLKView not being fully initialised for a couple of seconds and so using less cpu than normal and I get a speed boost? Any other ways I could structure the code to get the most performances in the loop?

Update I did some more testing, and noticed that the problem is also present when using a CAEAGLLayer instead of a GLKView, also that it doesn't happen on the Simulator, only on a device. I also tried with a OS X application with NSOpenGLView and it doesn't happen either...

Update 2 I tried starting the thread after a while instead of immediately, and if the delay is bigger than the time it usually takes for the drop to occur, the thread starts already slowed down... Not really sure what to make of it...

Metal Update I tried using Metal instead of OpenGL, using simple the stock template from Xcode, and it's happening with it too...

like image 888
Fabio Ritrovato Avatar asked Nov 01 '22 12:11

Fabio Ritrovato


1 Answers

The CPU frequency can be lowered by the OS to consume less energy / save battery. If your thread is not using much CPU power, then the OS will think it's a good time to lower the frequency. On a desktop computer on the other hand, there are many other threads / processes running (and the thresholds are probably very different), that's probably why it seems to work in the simulator / in a desktop app.

There are several possible reasons as why your thread is detected as not consuming much CPU time. One is that you call printf, and there is probably some sort of lock inside that makes your thread wait (CACurrentMediaTime maybe too). An another one is probably linked to the GLKView updates, although I'm not sure how.

like image 196
Jerem Avatar answered Nov 08 '22 02:11

Jerem