我作为一个有趣/有趣的项目在模拟器上工作,但我遇到了一些性能问题而未能弄清楚它们的来源。
应用程序主要由用于显示的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库存模板,它也发生了...
答案 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
使用这个循环不会减慢(无论是有无限循环还是在每一帧上做一堆操作),但我不完全确定为什么......