【发布时间】:2015-01-01 20:12:41
【问题描述】:
我正在开发一个模拟器作为一个附带/有趣的项目,但我遇到了一些性能问题并且无法弄清楚它们来自哪里。
应用程序主要由一个用于显示的 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 调试导航器中的 GPU 报告,我可以看到 CPU 帧时间为 0.2ms 然后,运行几秒钟后,循环下降到 1-5 MHz,CPU 帧时间增加到 0.6ms
如果我禁用 GLKView 更新,那么循环永远不会变慢
我也尝试使用不同的线程 API(gdc、NSThread、pthread),但这似乎没有任何影响
我的问题是,我在某处做错了吗?这只是 GLKView 没有完全初始化几秒钟的情况,因此使用的 cpu 比正常情况少,我得到了速度提升? 我可以通过其他方式构造代码以在循环中获得最大性能吗?
更新 我做了一些更多的测试,并注意到使用 CAEAGLLayer 而不是 GLKView 时也存在问题,而且它不会在模拟器上发生,仅在设备上发生。 我还尝试使用带有 NSOpenGLView 的 OS X 应用程序,但它也没有发生......
更新 2 我尝试在一段时间后而不是立即启动线程,如果延迟大于通常发生下降所需的时间,则线程启动速度已经减慢......不太确定该怎么做......
金属更新 我尝试使用 Metal 而不是 OpenGL,使用 Xcode 中的简单库存模板,它也正在发生...
【问题讨论】:
-
您不应该在任何线程上创建无限循环。您应该安排一个每帧运行一次的任务,并且每帧只执行一次它的任务。有很多方法可以做到这一点,但在使用显示链接更新/委托或 nstimer 之类的东西之前,首先检查 glkit 中是否内置了一些东西。可能的指针:stackoverflow.com/questions/13653113/…
-
抱歉,我确实需要一个无限循环,这就是模拟器的工作方式。每帧执行一项任务每秒钟最多可以给我 60 次“操作”,我需要的远不止这些(大约 1000000 倍左右……)对于屏幕更新,这很好,但不适用于 cpu 仿真
-
我认为您需要阅读更多有关仿真、多线程和同步工作原理的信息。假设您的模拟机器的 cpu 以 1 mhz 运行,并且您有一个命令队列,每个命令都需要已知数量的 cpu 周期来执行。然后,您将运行 CPU 可以在给定时间范围内执行的那些(例如 1500 条)命令,并在主机上模拟它们。然后你开始一个新的循环。这是一个非常简化的模型。您将不需要无限循环,并且必须有同步点(通常以模拟机器的 vsync 速率)。
-
您链接到的代码适用于桌面(win32)。考虑到您正在为移动设备开发,其中操作系统会采取措施防止应用程序消耗过多的 CPU 功率(耗尽电池),因此您的无限循环很可能是问题所在,因为从操作系统的角度来看,它看起来像一个线程锁定并可能需要限制或终止。由于您仅在 ios 上观察到这种情况,因此可能会证实我的观点(更多的预感)。至少尝试每隔一段时间(即每 1000 次迭代)产生一次线程,以测试它是否会改变观察到的运行时行为
标签: ios objective-c multithreading performance opengl-es