Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[render-test] Add gfx probe for tracking gpu resource usage #15843

Merged
merged 3 commits into from
Oct 30, 2019

Conversation

mpulkki-mapbox
Copy link
Contributor

No description provided.

struct RenderingStats {
bool isZero() const;

int numDrawCalls = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: RenderingStats() = default; ?

std::exception_ptr error;

map.renderStill([&](std::exception_ptr e) {
if (e) {
error = e;
} else {
result = backend->readStillImage();
result.image = backend->readStillImage();
result.stats = getBackend()->getContext().renderingStats();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

backend->getContext()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getBackend() is not a trivial getter function

@@ -17,6 +18,11 @@ class TransformState;

class HeadlessFrontend : public RendererFrontend {
public:
struct RenderResult {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall we add bool isValid() const here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah could be added. In current use std::exception is thrown if an error is encountered

namespace gfx {

struct RenderingStats {
bool isZero() const;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isEmpty() ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would say that being "empty" is not the right term in this context.

@@ -48,7 +54,7 @@ class HeadlessFrontend : public RendererFrontend {
LatLng latLngForPixel(const ScreenCoordinate&);

PremultipliedImage readStillImage();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shall readStillImage() return RenderResult too? (Might be added later)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting function as it has to be called from the rendering thread. It can be used together with the Map::renderStill(...) to fetch the still image in the callback.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be updated later.

@@ -82,13 +88,33 @@ struct NetworkProbe {
size_t transferred;
};

struct GfxProbe {
struct Memory {
int allocated = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

size_t

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory tracking between probeGFXStart and probeGFXEnd is relative, ie. these numbers could be negative in a tracking segment where more memory was released than allocated. I might need to rethink the logic :)

GfxProbe() = default;
GfxProbe(const mbgl::gfx::RenderingStats&);

int numDrawCalls = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: no need = 0

Copy link
Contributor Author

@mpulkki-mapbox mpulkki-mapbox Oct 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will lead to uninitialized memory, for example innocent looking initialization GfxProbe probe; will result in undefined behavior.

Copy link
Contributor Author

@mpulkki-mapbox mpulkki-mapbox Oct 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course GfxProbes could be initialized like GfxProbe probe {}; but that's really dangerous and error prone code imho.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GfxProbe() = default; shall solve it for you

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I solved the issue for now by properly using aggregate initialization GfxProbe probe {} instead of more traditional GfxProbe probe; initialization

@@ -34,6 +34,27 @@

using namespace mbgl;

GfxProbe::GfxProbe(const mbgl::gfx::RenderingStats& stats) {
numBuffers = stats.numBuffers;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use init list

const char* msg, const std::string& name, const auto& expected, const auto& actual) -> bool {
if (expected != actual) {
char msgBuf[512];
snprintf(msgBuf, sizeof(msgBuf), msg, name.c_str(), actual, expected);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could std::stringstream be used instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the c-style printf formatting makes the code more readable (in this case) for the caller.

@@ -206,10 +207,12 @@ UniqueTexture Context::createUniqueTexture() {
if (pooledTextures.empty()) {
pooledTextures.resize(TextureMax);
MBGL_CHECK_ERROR(glGenTextures(TextureMax, pooledTextures.data()));
stats.numCreatedTextures += TextureMax;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this statistics population affect the performance? shall we collect it conditionally, e.g. for debug builds only? @alexshalamov @astojilj

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incrementing one integer value wont have any visible effect on performance :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true, but I mean the whole stats collecting in general, e.g. std::chrono::steady_clock::now() might not be that lightweight

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's good idea to collect general rendering stats (in gl::Context). Frame time tracking in headless frontend could be collected conditionally, but impact on performance is neglectable nevertheless.

auto check = [&metadata](
const char* msg, const std::string& name, const auto& expected, const auto& actual) -> bool {
if (expected != actual) {
char msgBuf[512];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe use string stream instead of hardcoded buffer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately snprintf requires a fixed buffer. C-style formatting is used here for more readable code.

const auto& expectedValue = expected.second;
const auto& actualValue = actual->second;

if (!check("Number of draw calls at probe \"%s\" is %i, expected is %i",
Copy link
Contributor

@alexshalamov alexshalamov Oct 23, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to check all probes and return 'false' if one of probe fails. Also, are all expected values (probes) mandatory?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good point!

@mpulkki-mapbox mpulkki-mapbox force-pushed the mpulkki-gfx-probe branch 4 times, most recently from e4278e1 to de9bfb1 Compare October 24, 2019 14:10
@@ -647,6 +666,7 @@ void Context::performCleanup() {
}
}
MBGL_CHECK_ERROR(glDeleteBuffers(int(abandonedBuffers.size()), abandonedBuffers.data()));
stats.numBuffers -= (int)abandonedBuffers.size();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: better int(..) or static_cast()

return false;
}

auto check = [&metadata](
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this still needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, not anymore!

std::stringstream ss;
ss << "Number of textures at probe \"" << probeName << "\" is " << actualValue.numTextures
<< ", expected is " << expectedValue.numTextures;
if (metadata.errorMessage.length()) ss << "\n";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::endl

Copy link
Contributor

@pozdnyakov pozdnyakov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm % comments

std::stringstream ss;
ss << "Number of textures at probe \"" << probeName << "\" is " << actualValue.numTextures
<< ", expected is " << expectedValue.numTextures;
if (metadata.errorMessage.length()) ss << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should it be checked before adding the new error message?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All failed test cases of a probe are reported in a single message. Should this behavior be changed?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean, should std::endl be added first i.e. as a separator between the different probe reports?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (!metadata.errorMessage.empty()) ss << std::endl;
ss << "Number of textures at probe \"" << probeName << "\" is " << actualValue.numTextures
               << ", expected is " << expectedValue.numTextures;

Copy link
Contributor Author

@mpulkki-mapbox mpulkki-mapbox Oct 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, metadata is shared between different operations.

std::stringstream ss;
ss << "Number of textures at probe \"" << probeName << "\" is " << actualValue.numTextures
<< ", expected is " << expectedValue.numTextures;
if (metadata.errorMessage.length()) ss << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: !metadata.errorMessage.empty()

@mpulkki-mapbox mpulkki-mapbox force-pushed the mpulkki-gfx-probe branch 3 times, most recently from 3b8d19f to 192fcc5 Compare October 29, 2019 13:31
@mpulkki-mapbox mpulkki-mapbox merged commit 6900ac9 into master Oct 30, 2019
@mpulkki-mapbox mpulkki-mapbox deleted the mpulkki-gfx-probe branch October 30, 2019 12:32
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants