Skip to content

Commit cc3a321

Browse files
committed
Merge branch 'feat/pciutils_get_gpu_speed'
2 parents 13b7383 + 598d018 commit cc3a321

File tree

16 files changed

+644
-51
lines changed

16 files changed

+644
-51
lines changed

.clang-format

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
BasedOnStyle: GNU
1+
BasedOnStyle: Microsoft
22

33
TabWidth: 4
44
IndentWidth: 4
@@ -13,3 +13,5 @@ PenaltyReturnTypeOnItsOwnLine: 1000
1313
ColumnLimit: 100
1414
BreakBeforeBraces: Mozilla
1515
SpaceBeforeParens: Never
16+
AllowShortEnumsOnASingleLine: false
17+
AllowShortFunctionsOnASingleLine: None

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"name": "(Windows) Launch",
99
"type": "cppvsdbg",
1010
"request": "launch",
11-
"program": "builddir/src/pciutils_template.exe",
11+
"program": "builddir/src/gpu_speed.exe",
1212
"args": [],
1313
"stopAtEntry": true,
1414
"cwd": "${workspaceRoot}",

assets/meson.build

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11

22
# download PCI IDs database
3-
# update-pciids.cmd places output in cwd so we need to copy it into build folder first
4-
fs = import('fs')
5-
update_pciids = fs.copyfile('update-pciids.cmd')[0]
6-
pciids = custom_target('update_pciids', command: update_pciids, output: 'pci.ids.gz')
3+
pciids = custom_target('update_pciids', command: ['update-pciids.cmd', '@OUTPUT@'], output: 'pci.ids.gz')
74

85
windows = import('windows')
96
program_rc = windows.compile_resources('program_rc.rc', include_directories:'../src', depends: pciids)

assets/program_icon.ico

-57.2 KB
Binary file not shown.

assets/update-pciids.cmd

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@set @foo=1 /*
22
@echo off
3-
cscript %0 //E:JScript //Nologo
3+
cscript %0 //E:JScript //Nologo %1
44
goto end
55
*/;
66

@@ -10,6 +10,10 @@ var adSaveCreateOverWrite = 2;
1010
var SRC = "http://pci-ids.ucw.cz/v2.2/pci.ids.gz";
1111
var DEST = "pci.ids.gz";
1212

13+
if(WScript.Arguments.length == 1) {
14+
DEST = WScript.Arguments(0)
15+
}
16+
1317
var XMLHTTP = new ActiveXObject("MSXML2.XMLHTTP");
1418
XMLHTTP.open("GET", SRC, false);
1519
XMLHTTP.send();

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
project('pciutils_template', ['c','cpp'],
1+
project('gpu_speed', ['c','cpp'],
22
version : run_command('git', 'describe', '--tags', check: true).stdout().strip().replace('v',''),
33
default_options : ['warning_level=3', 'c_std=c17', 'cpp_std=c++20'])
44

src/console.c

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
#include <fcntl.h>
2+
#include <io.h>
3+
#include <stdio.h>
4+
#include <windows.h>
5+
6+
#include "console.h"
7+
8+
static bool attached_console = false;
9+
static bool allocated_console = false;
10+
11+
void console_init(void)
12+
{
13+
attached_console = AttachConsole(ATTACH_PARENT_PROCESS);
14+
if(!attached_console) {
15+
allocated_console = AllocConsole();
16+
}
17+
18+
// don't mess with file handles in case of console application
19+
if(!attached_console && !allocated_console) {
20+
return;
21+
}
22+
23+
FILE *dummy = NULL;
24+
freopen_s(&dummy, "CONOUT$", "wt", stdout);
25+
freopen_s(&dummy, "CONOUT$", "wt", stderr);
26+
freopen_s(&dummy, "CONIN$", "r", stdin);
27+
28+
// clear command prompt that was printed into the first line
29+
if(attached_console) {
30+
printf("\33[2K\r");
31+
}
32+
}
33+
34+
void console_free(void)
35+
{
36+
// send fake enter code to unblock command line after exit
37+
if(attached_console) {
38+
SendMessage(GetConsoleWindow(), WM_CHAR, VK_RETURN, 0);
39+
}
40+
41+
if(attached_console || allocated_console) {
42+
FreeConsole();
43+
}
44+
}
45+
46+
// returns true if current console is attached to parent terminal window
47+
bool console_is_attached(void)
48+
{
49+
return attached_console;
50+
}
51+
52+
// returns true if separate console window has been allocated
53+
bool console_is_allocated(void)
54+
{
55+
return allocated_console;
56+
}
57+
58+
// blocks till any key is pressed
59+
void console_wait_anykey(void)
60+
{
61+
DWORD cc;
62+
INPUT_RECORD irec;
63+
while(ReadConsoleInput(GetStdHandle(STD_INPUT_HANDLE), &irec, 1, &cc)) {
64+
if(irec.EventType == KEY_EVENT && ((irec.Event).KeyEvent).bKeyDown)
65+
break;
66+
}
67+
}

src/console.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#pragma once
2+
3+
#include <stdbool.h>
4+
5+
void console_init(void);
6+
void console_free(void);
7+
8+
// returns true if current console is attached to parent terminal window
9+
bool console_is_attached(void);
10+
11+
// returns true if separate console window has been allocated
12+
bool console_is_allocated(void);
13+
14+
// blocks till any key is pressed
15+
void console_wait_anykey(void);

src/main.c

Lines changed: 110 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,119 @@
1+
#include <math.h>
2+
#include <stdbool.h>
13
#include <stdio.h>
4+
#include <stdlib.h>
5+
#include <windows.h>
26

3-
#include "pci.h"
4-
#include "rc_manager.h"
7+
#include "console.h"
8+
#include "pcie_speed.h"
9+
#include "toast.h"
510

6-
/*
7-
* The PCI Library -- Example of use (simplistic lister of PCI devices)
8-
*
9-
* Written by Martin Mares and put to public domain. You can do
10-
* with it anything you want, but I don't give you any warranty.
11-
*/
12-
static int pcilib_main(void)
11+
#define PCI_CLASS_VGA "0300"
12+
#define PCI_FILTER_STR "::" PCI_CLASS_VGA
13+
14+
#define TOAST_SLEEP_MS (60 * 1000)
15+
16+
#define COMMAND_QUIET L"--quiet"
17+
#define COMMAND_QUIET_SHORT L"-q"
18+
#define COMMAND_ALWAYS_TOAST L"--always"
19+
#define COMMAND_ALWAYS_TOAST_SHORT L"-a"
20+
21+
static int check_gpu_speed(bool *const toast_shown, const bool always_show_toast)
1322
{
14-
struct pci_access *pacc;
15-
struct pci_dev *dev;
16-
unsigned int c;
17-
char namebuf[1024], *name;
18-
19-
pacc = pci_alloc(); /* Get the pci_access structure */
20-
/* Set all options you want -- here we stick with the defaults */
21-
pci_init(pacc); /* Initialize the PCI library */
22-
pci_scan_bus(pacc); /* We want to get the list of devices */
23-
for(dev = pacc->devices; dev; dev = dev->next) /* Iterate over all devices */
24-
{
25-
pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES
26-
| PCI_FILL_CLASS); /* Fill in header info we need */
27-
c = pci_read_byte(dev, PCI_INTERRUPT_PIN); /* Read config register directly */
28-
printf("%04x:%02x:%02x.%d vendor=%04x device=%04x class=%04x irq=%d (pin %d) base0=%lx",
29-
dev->domain, dev->bus, dev->dev, dev->func, dev->vendor_id, dev->device_id,
30-
dev->device_class, dev->irq, c, (long)dev->base_addr[0]);
31-
32-
/* Look up and print the full name of the device */
33-
name = pci_lookup_name(pacc, namebuf, sizeof(namebuf), PCI_LOOKUP_DEVICE, dev->vendor_id,
34-
dev->device_id);
35-
printf(" (%s)\n", name);
36-
}
37-
pci_cleanup(pacc); /* Close everything */
38-
return 0;
23+
struct pcie_speed_data pci = {0};
24+
25+
if(pcie_speed_get(PCI_FILTER_STR, &pci) != EXIT_SUCCESS) {
26+
fprintf(stderr, "Failed to get PCIe device data\n");
27+
return EXIT_FAILURE;
28+
}
29+
30+
for(size_t i = 0; i < pci.len; i++) {
31+
32+
struct pcie_speed_entry *entry = &pci.data[i];
33+
34+
printf("%s\n", entry->name);
35+
printf("\tLnkCap:\tMaximum Link Speed %s, Maximum Link Width x%d\n",
36+
pcie_speed_to_str(entry->lnk_cap_speed), entry->lnk_cap_width);
37+
printf("\tLnkSta:\tNegotiated Link Speed %s, Negotiated Link Width x%d\n",
38+
pcie_speed_to_str(entry->lnk_sta_speed), entry->lnk_sta_width);
39+
printf("\tLnkCap2: Supported Link Speed: 2.5GT/s - %s\n",
40+
pcie_speed_to_str(entry->lnk_cap2_speed));
41+
printf("\tLnkCtl2: Target Link Speed: %s\n", pcie_speed_to_str(entry->lnk_ctl2_speed));
42+
43+
// device is operating at suboptimal speed
44+
if((entry->lnk_cap_speed < entry->lnk_cap2_speed) ||
45+
(entry->lnk_sta_speed < entry->lnk_cap2_speed) || always_show_toast) {
46+
char buff[1024] = {0};
47+
snprintf(buff, sizeof(buff), "PCIe speed %s instead of %s",
48+
pcie_speed_to_str(min(entry->lnk_cap_speed, entry->lnk_sta_speed)),
49+
pcie_speed_to_str(entry->lnk_cap2_speed));
50+
51+
toast_show("GPU Speed error", entry->name, buff, TOAST_SLEEP_MS);
52+
53+
*toast_shown = true;
54+
55+
printf("Warning: device is operating at suboptimal speed %s instead of %s\n",
56+
pcie_speed_to_str(min(entry->lnk_cap_speed, entry->lnk_sta_speed)),
57+
pcie_speed_to_str(entry->lnk_cap2_speed));
58+
}
59+
}
60+
61+
pcie_speed_data_free(&pci);
62+
63+
return EXIT_SUCCESS;
3964
}
4065

41-
int main(void)
66+
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
4267
{
43-
// unpack all required resources
44-
if(rc_manager_init() == 0) {
45-
// do something useful with pcilib
46-
return pcilib_main();
68+
UNREFERENCED_PARAMETER(hInstance);
69+
UNREFERENCED_PARAMETER(hPrevInstance);
70+
UNREFERENCED_PARAMETER(nCmdShow);
71+
72+
int ret = EXIT_SUCCESS;
73+
bool toast_shown = false;
74+
bool always_show_toast = false;
75+
bool hide_console = false;
76+
77+
int argc = 0;
78+
LPWSTR *argv = CommandLineToArgvW(pCmdLine, &argc);
79+
80+
for(int i = 0; i < argc; i++) {
81+
if(!wcscmp(COMMAND_QUIET, argv[i]) || !wcscmp(COMMAND_QUIET_SHORT, argv[i])) {
82+
hide_console = true;
83+
} else if(!wcscmp(COMMAND_ALWAYS_TOAST, argv[i]) ||
84+
!wcscmp(COMMAND_ALWAYS_TOAST_SHORT, argv[i])) {
85+
always_show_toast = true;
86+
}
87+
}
88+
89+
console_init();
90+
91+
if(hide_console && console_is_allocated()) {
92+
ShowWindow(GetConsoleWindow(), SW_HIDE);
93+
}
94+
95+
if(toast_init() != TOAST_RESULT_SUCCESS) {
96+
fprintf(stderr, "Failed to initialize toast\n");
97+
ret = EXIT_FAILURE;
98+
goto exit;
4799
}
48-
return 1;
100+
101+
if(check_gpu_speed(&toast_shown, always_show_toast) != EXIT_SUCCESS) {
102+
ret = EXIT_FAILURE;
103+
goto exit;
104+
}
105+
106+
if(!toast_shown && !hide_console && console_is_allocated()) {
107+
printf("Press any key...\n");
108+
console_wait_anykey();
109+
}
110+
111+
if(toast_shown) {
112+
Sleep(TOAST_SLEEP_MS);
113+
}
114+
115+
exit:
116+
117+
console_free();
118+
return ret;
49119
}

src/meson.build

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
11
src_files = [
22
'main.c',
33
'rc_manager.c',
4+
'pcie_speed.c',
5+
'console.c',
6+
'toast.cpp',
47
program_rc,
58
]
69

710
inc_dirs = include_directories('.')
811

912
pciutils_dep = dependency('pciutils', required: true)
1013

14+
# add WinToast library
15+
cmake = import('cmake')
16+
wintoast_var = cmake.subproject_options()
17+
wintoast_var.add_cmake_defines({'WINTOASTLIB_BUILD_EXAMPLES': false})
18+
wintoast_var.add_cmake_defines({'WINTOASTLIB_QT_ENABLED': false})
19+
wintoast_var.set_override_option('warning_level', '2')
20+
21+
if get_option('buildtype') == 'release'
22+
wintoast_var.add_cmake_defines({'CMAKE_BUILD_TYPE': 'release'})
23+
endif
24+
25+
wintoast_pro = cmake.subproject('wintoast', options: wintoast_var, required: true)
26+
wintoast_dep = wintoast_pro.dependency('WinToast')
27+
1128
deps = [
1229
pciutils_dep,
30+
wintoast_dep,
1331
]
1432

1533
# run executable as administrator
@@ -18,4 +36,4 @@ link_args = [
1836
'/MANIFESTUAC:level=\'requireAdministrator\'',
1937
]
2038

21-
executable(meson.project_name(), src_files, include_directories: inc_dirs, dependencies: deps, win_subsystem:'console', link_args: link_args)
39+
executable(meson.project_name(), src_files, include_directories: inc_dirs, dependencies: deps, win_subsystem:'windows', link_args: link_args)

0 commit comments

Comments
 (0)