-
Notifications
You must be signed in to change notification settings - Fork 16.2k
feat: Implementation of getGPUInfo API. #13486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This is the example response of the API.
|
|
You might want to take out the |
atom/browser/api/atom_api_app.cc
Outdated
@@ -1162,6 +1163,14 @@ v8::Local<v8::Value> App::GetGPUFeatureStatus(v8::Isolate* isolate) { | |||
return mate::ConvertToV8(isolate, status ? *status : temp); | |||
} | |||
|
|||
v8::Local<v8::Value> App::GetGPUInfo(v8::Isolate* isolate) { | |||
const auto& gpu_info = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you may need to call content::GpuDataManagerImpl::GetInstance()->RequestCompleteGpuInfoIfNeeded()
to make the information available
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Milan! I'll try that and will update the PR. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That worked. Was able to fetch all the info with that.
This API looks a bit awkward. How about making it
const info = await app.getGPUInfo('full');
// or
const info = await app.getGPUInfo('short');
// potentially use 'short' as default so above is the same as:
const info = await app.getGPUInfo(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few typos, but otherwise the docs look good.
docs/api/app.md
Outdated
@@ -904,6 +904,15 @@ Returns [`ProcessMetric[]`](structures/process-metric.md): Array of `ProcessMetr | |||
|
|||
Returns [`GPUFeatureStatus`](structures/gpu-feature-status.md) - The Graphics Feature Status from `chrome://gpu/`. | |||
|
|||
### `app.getGPUInfo([callback])` | |||
|
|||
Returns `Object` - GPU Information available in chromium's GPUInfo object. It's contains the version and driver information that's shown on `chrome://gpu` page. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: It's contains
docs/api/app.md
Outdated
* `callback` Function (optional) | ||
* `gpuInfo` Object - List of all attributes and values available in [chromium's GPUInfo object](https://chromium.googlesource.com/chromium/src/gpu/+/master/config/gpu_info.cc). | ||
|
||
Providing the optional callback will fetch the complete information available from the GPU process. In this case, the callback object will have all the available information, which can be more that what the returned object had. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type: more that
should be more than
.
Can you also explain why the callback function will yield more results than the returned object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @zeke! I'll update these with the other changes. 👍
Thanks @YurySolovyov . I like your idea. However, the main idea here was to get the short information synchronously, so that apps can immediately act upon it. It most likely would be used at startup, so getting the minimal information synchronously is better. |
I would argue that consistency is better. Besides, promises work well with async/await so that it can be used even at startup with almost the same ergonomics |
docs/api/app.md
Outdated
@@ -904,6 +904,15 @@ Returns [`ProcessMetric[]`](structures/process-metric.md): Array of `ProcessMetr | |||
|
|||
Returns [`GPUFeatureStatus`](structures/gpu-feature-status.md) - The Graphics Feature Status from `chrome://gpu/`. | |||
|
|||
### `app.getGPUInfo([callback])` | |||
|
|||
Returns `Object` - GPU Information available in chromium's GPUInfo object. It's contains the version and driver information that's shown on `chrome://gpu` page. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning an object and accepting a callback 😕
Would it be better to callback with everything, it seems really weird for a single API to be both synchronous and asynchronous
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, it definitely is hacky. I'm leaning towards the promise way now. Will make changes and update the branch. Thanks @MarshallOfSound and @YurySolovyov !
docs/api/app.md
Outdated
Returns `Object` - GPU Information available in chromium's GPUInfo object. It's contains the version and driver information that's shown on `chrome://gpu` page. | ||
|
||
* `callback` Function (optional) | ||
* `gpuInfo` Object - List of all attributes and values available in [chromium's GPUInfo object](https://chromium.googlesource.com/chromium/src/gpu/+/master/config/gpu_info.cc). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please use a link to a Chromium release tag, not to a master
?
That file might get renamed or removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I thought of doing that. We don't do that in other places in the docs though. Also, we should add another item on the release checklist to update the docs.
spec/api-app-spec.js
Outdated
const activeDevice = gpuInfo.gpuDevice.find((device) => { | ||
return device.active === true | ||
}) | ||
expect(activeDevice).to.not.be.null() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Array#find()
returns undefined
if nothing is found.
Can you please check that activeDevice
is an object instead of !== null
?:
expect(activeDevice).to.be.an('object')
spec/api-app-spec.js
Outdated
return device.active === true | ||
}) | ||
expect(activeDevice).to.not.be.null() | ||
expect(activeDevice.deviceId).to.be.a('number').not.lessThan(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it would be better to check for deviceId
property existence first.
It will produce a failure message better than expected undefined to be a number
.
expect(activeDevice).to.have.property('deviceId').that.is.a('number').not.lessThan(0)
docs/api/app.md
Outdated
@@ -904,6 +904,14 @@ Returns [`ProcessMetric[]`](structures/process-metric.md): Array of `ProcessMetr | |||
|
|||
Returns [`GPUFeatureStatus`](structures/gpu-feature-status.md) - The Graphics Feature Status from `chrome://gpu/`. | |||
|
|||
### `app.getGPUInfo(info_type)` | |||
|
|||
* `info_type` String. Values can be either 'available' for currently available info or `complete` for complete info. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Docs are not consistent with tests: test use
full
/short
and docs saycomplete
/available
- Camel case
info_type
->infoType
orInfoType
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, still working on this PR. I have those changes made locally.
atom/browser/api/atom_api_app.cc
Outdated
@@ -1162,6 +1195,30 @@ v8::Local<v8::Value> App::GetGPUFeatureStatus(v8::Isolate* isolate) { | |||
return mate::ConvertToV8(isolate, status ? *status : temp); | |||
} | |||
|
|||
util::Promise* App::GetGPUInfo(const std::string& info_type) { | |||
CHECK(!is_fetching_gpuinfo_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is scary
Can't we just return gpinfo_promise_
instead here 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good idea.
atom/browser/api/atom_api_app.h
Outdated
@@ -228,6 +232,10 @@ class App : public AtomBrowserClient::Delegate, | |||
|
|||
base::FilePath app_path_; | |||
|
|||
util::Promise* gpuinfo_promise_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we explicitly initialize this to nullptr
, if people do a truthy check on this in the future it wouldn't work without explicit initialization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm doing that in the constructor.
atom/browser/api/atom_api_app.h
Outdated
@@ -228,6 +232,10 @@ class App : public AtomBrowserClient::Delegate, | |||
|
|||
base::FilePath app_path_; | |||
|
|||
util::Promise* gpuinfo_promise_; | |||
bool has_complete_gpu_info_; | |||
bool is_fetching_gpuinfo_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A truthy check on gpuinfo_promise_
could replace this variable right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not exactly. Also actually I'm still working on the changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if we return the same promise, then we don't need the variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please initialize the values here, we are using C++11 class member variable initialization:
#13030
atom/browser/api/atom_api_app.h
Outdated
@@ -228,6 +232,10 @@ class App : public AtomBrowserClient::Delegate, | |||
|
|||
base::FilePath app_path_; | |||
|
|||
util::Promise* gpuinfo_promise_; | |||
bool has_complete_gpu_info_; | |||
bool is_fetching_gpuinfo_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please initialize the values here, we are using C++11 class member variable initialization:
#13030
atom/browser/api/atom_api_app.cc
Outdated
if (info_type == "complete") { | ||
// In this case, we create an object on the heap and GPUInfoManager is | ||
// responsible for deleting it | ||
GPUInfoManager* info_mgr = new GPUInfoManager(isolate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there something like enable_shared_from_this
for chromium, so that I do not have to do this memory management dance?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GPUInfoManager
can be a base::Singleton<>
, which takes ownership of the util::Promise
. This also allows the class to be moved outside the api layer.
atom/browser/api/atom_api_app.cc
Outdated
return promise; | ||
} | ||
const auto gpu_data_manager = content::GpuDataManagerImpl::GetInstance(); | ||
if (!gpu_data_manager->GpuAccessAllowed(nullptr)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This check can be merged with the previous one,
if (info_type != "..." || !gpu_data_manager->GpuAccessAllowed(nullptr))
atom/browser/api/atom_api_app.cc
Outdated
@@ -1162,6 +1164,33 @@ v8::Local<v8::Value> App::GetGPUFeatureStatus(v8::Isolate* isolate) { | |||
return mate::ConvertToV8(isolate, status ? *status : temp); | |||
} | |||
|
|||
util::Promise* App::GetGPUInfo(v8::Isolate* isolate, | |||
const std::string& info_type) { | |||
if (info_type != "available" && info_type != "complete") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you rename available
to basic
, the former seems too generic. Also the result from CollectBasicGraphicsInfo
seems fixed, it would be best to list the data from it in the docs explicitly, that way users would have better idea to choose among the options.
atom/browser/api/gpuinfo_manager.cc
Outdated
if (NeedsCompleteGpuInfoCollection()) { | ||
gpu_data_manager_->RequestCompleteGpuInfoIfNeeded(); | ||
} else { | ||
content::BrowserThread::PostTask( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was the idea here to delay the call till next tick ? If so, use the thread task runner and post tasks with it.
atom/browser/api/atom_api_app.cc
Outdated
if (info_type == "complete") { | ||
// In this case, we create an object on the heap and GPUInfoManager is | ||
// responsible for deleting it | ||
GPUInfoManager* info_mgr = new GPUInfoManager(isolate); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GPUInfoManager
can be a base::Singleton<>
, which takes ownership of the util::Promise
. This also allows the class to be moved outside the api layer.
@zeke @miniak @deepak1556 @YurySolovyov Please let me know how you feel about this change now? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API shape looks good to me. Haven't studied the implementation.
atom/browser/api/atom_api_app.cc
Outdated
const auto& promise = new util::Promise(isolate); | ||
if ((info_type != "basic" && info_type != "complete") || | ||
!gpu_data_manager->GpuAccessAllowed(nullptr)) { | ||
promise->Reject(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we reject with a helpful error message here?
docs/api/app.md
Outdated
|
||
For `infoType` equal to `basic`: | ||
Promise is fulfilled with `Object` containing fewer attributes than when requested with `complete`. Here's an example of basic response: | ||
```json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change this to js
to make it highlighted correctly
What's the current status of this PR? |
a76a461
to
6e072a9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, Thanks!
docs are looking good now
Release Notes Persisted
|
* Implementation of getGPUInfo API. * Clear promise set * Changes to promise usage * Minor fixes * Fix linux build * Update spec * Fix lint (linter didn't run on windows locally) * Test running single test for CI * Update spec
This PR implements the
app.getGPUInfo
api to get the GPU details available onchrome://gpu
.This can be useful to clients for various purposes like working around bugs based on available details.
Chromium GPUInfo class provides an interface for an enumerator. Creating a custom enumerator and calling
EnumerateFields
on theGPUInfo
class, will get us all the attributes in the class. Using this enumerator also saves us the maintenance burden when attributes are added/changed with newer versions of chromium.I haven't updated the docs or added tests yet, will do that once I get some feedback on the API.
Checklist
npm test
passesNotes: Implemented new
getGPUInfo
API to get details about the GPU.