Open GL +无限循环使神秘性能下降

时间:2015-01-01 20:12:42

标签: ios objective-c multithreading performance opengl-es

我作为一个有趣/有趣的项目在模拟器上工作,但我遇到了一些性能问题而未能弄清楚它们的来源。

应用程序主要由用于显示的GLKView和用于cpu仿真的具有无限循环的单独线程组成。这是一个样本,其中包含所有实际仿真代码,但仍显示问题:

@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
像这样,无限循环基本上只是计算它的迭代次数并以MHz为单位打印出它的频率。

所以,问题是,当应用程序启动时,循环运行在大约9-15 MHz(在iPhone6上),如果我在Xcode的Debug Navigator中查看GPU报告,我可以看到CPU帧时间为0.2ms 然后,运行几秒后,循环降至1-5 MHz,CPU帧时间增加到0.6 ms

如果我禁用GLKView更新,那么循环永远不会变慢

我也尝试使用不同的线程API(gdc,NSThread,pthread),但这似乎没有任何影响

我的问题是,我在某处做错了吗?这只是一个GLKView没有完全初始化几秒钟的情况,所以使用比正常情况更少的CPU,我得到一个速度提升? 我可以用其他任何方式构造代码以获得循环中的最佳性能吗?

更新 我做了一些测试,并注意到使用CAEAGLLayer而不是GLKView时也存在问题,并且它不会在模拟器上发生,只在设备上发生。 我也尝试过使用NSOpenGLView的OS X应用程序,它也不会发生...

更新2 我尝试在一段时间后启动线程而不是立即启动线程,并且如果延迟大于通常需要的时间,那么线程开始已经放慢了......不确定要做什么...

金属更新 我尝试使用Metal而不是OpenGL,使用简单的Xcode库存模板,它也发生了...

2 个答案:

答案 0 :(得分:2)

操作系统可以降低CPU频率以降低能耗/节省电池电量。如果您的线程没有使用太多的CPU电源,那么操作系统会认为这是降低频率的好时机。另一方面,在台式计算机上,还有许多其他线程/进程在运行(并且阈值可能非常不同),这可能是它似乎在模拟器/桌面应用程序中工作的原因。

有几个可能的原因导致您的线程被检测为不占用大量CPU时间。一个是你调用printf,内部可能存在某种锁定使你的线程等待(CACurrentMediaTime也可能)。另一个可能与GLKView更新有关,但我不确定如何。

答案 1 :(得分:0)

所以,我仍然无法弄清楚它为什么会发生,但我设法找到一种解决方法,使用由CGBitmapContext支持的CALayer而不是使用受https://github.com/lmmenge/MeSNEmu启发的OpenGL,

@interface GraphicLayer : CALayer
{
    CGContextRef _context;
}
@end

@implementation GraphicLayer

-(id)init
{
    self = [super init];
    if (self) {
        CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
        _context = CGBitmapContextCreate(NULL, 418, 263, 8, 418 * 4, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
        CFRelease(colorSpace);
    }
    return self;
}

- (void)display
{
    CGImageRef CGImage = CGBitmapContextCreateImage(_context);
    self.contents = (__bridge id)(CGImage);
    CGImageRelease(CGImage);
}

@end

@interface GraphicView : UIView
@end

@implementation GraphicView

+ (Class)layerClass
{
    return [GraphicLayer class];
}

- (void)drawRect:(CGRect)rect
{
}

@end

使用这个循环不会减慢(无论是有无限循环还是在每一帧上做一堆操作),但我不完全确定为什么......