8

I am currently working on an OpenGl program whose performance I would like to improve. The performance is okay but not ideal on powerful dedicated GPUs, but is abysmal on integrated graphics (< 10 fps). In a normal program (CPU-based, no OpenGl or other GPU API), I would run a profiler (perhaps the one built into CLion) on the program, see where most of the time is spent, and then work on a better algorithm for those areas or find a way to reduce the amount that that area is called.

Using this technique on my OpenGl program shows that the vast majority of the program's time (~86%) on its main thread (the one that I want to optimize) is spent in the OpenGl driver's .so file. Additionally, the CPU usage of the program while it is running is very low, but the GPU usage hovers between 95% and 100%. Taken together, these pieces of information tell me that the bottleneck is in the GPU, so that is where I should optimize.

This where a problem occurs. My normal technique of using using a profiler to guide my optimizations won't work without s specific GPU profiler, however. As such, I did some research to find a profiler that will tell me where GPU processing time is being spent. I could not find anything that is remotely usable. Everything was either Windows-only (I run exclusively Linux, and my program isn't ported to Windows yet -- nor will it be until it is much further along), no longer updated, and/or costs way more than the budget for this project is.

As such, I ask: how can I optimize my program's performance when the relevant profiler does not exist? I tried guessing where the issues are and optimizing from that, however it made no difference whatsoever even though I was able to ascertain that my optimizations (frustum culling) did result in less work for the GPU by about half. A good answer will give some profiling technique that is applicable to Opengl on Linux, or will give a technique that works without a profiler.

4
  • thebold fashioned way of commenting stuff out untill you find the slow bit?
    – Ewan
    Commented Jun 8, 2019 at 20:25
  • @ewan the renderer is quite minimal. Commenting anyrhing out would make it not work.
    – john01dav
    Commented Jun 8, 2019 at 20:30
  • As to the "commenting stuff" piece, you could split the code up into sections, then comment everything except for the first section. These sections should have some output to verify that it works as expected. Once you have that, you can step through the sections to see if that piece is the potential bottleneck. With this approach, you wind up with the basic trial and error style of testing. Commented Jun 9, 2019 at 4:49
  • If you have access to a hardware pin on the GPU you could toggle it on entry and exit to functions. An oscilloscope will then indicate time spent in that function and how often it is called etc.
    – Ant
    Commented Jun 10, 2019 at 15:04

1 Answer 1

7

how can I optimize my program's performance when the relevant profiler does not exist?

By profiling your code yourself. Finding GPU bottlenecks is not particularly difficult.

Assuming you have an inferior version of OpenGL (timer queries are not available), then you do what people have been doing for years: change stuff and see how it works.

There are three basic locations for bottlenecks in rendering: CPU (ie: inefficiently sending data), vertex T&L, and per-fragment processing. Determining which is the bottleneck is merely a matter of seeing the performance impact when you change something.

For example, if you want to see if per-fragment processing is a bottleneck, reduce the number of fragments generated (ie: the resolution of the screen). If performance improves at a linear rate with respect to the number of pixels in the screen resolution, then that was your bottleneck.

If you want to know if your vertex processing is the bottleneck, then render the same object multiple times (one after the other). Assuming you have depth testing active and aren't doing blending, the fragments from the subsequent renderings should be culled before invoking the fragment shader. So if performance linearly drops from repeatedly rendering all of objects, then you have a vertex processing bottleneck.

And if neither of those are the bottleneck, then by process of elimination, the CPU is the issue.

If you have access to timer queries, then you can time GPU operations directly. You can't time specific stages, but you can determine the time it takes for GPU commands to complete. You can also find the latency between GPU command completion and when the CPU thread finished sending those commands. Overall, these should help you tell how long it takes for the GPU to process stuff compared to the CPU sending it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.