diff --git a/README.md b/README.md index cbbb020..224f458 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,66 @@ +# Godot GitHub issue statistics + +This repository gathers hardware and software information reported by users on the +[issue tracker of the main Godot repository](https://github.com/godotengine/godot/issues). +This information is then displayed on a [website](https://godotengine.github.io/issue-stats/). + +As such, these statistics are not representative of the entire Godot community, +but they allow seeing what kind of hardware and software is popular among issue reporters. + +## How it works + +### Backend + +- Using GitHub's GraphQL API, 30 requests are performed to fetch the + description, author and creation date of the 3,000 latest issues. +- In the resulting data, the `System information` field of the issue is parsed + in a case-sensitive, punctuation-insensitive manner. + - The operating system, CPU and GPU is detected using this information + provided by the user. All other information (such as the number of physical + cores or amount of video memory) is inferred from the model names reported + by the user.[^1] + - If there's no valid `System information` section or it contains no usable + information, the issue is ignored. +- A dictionary of `set()` values is created with all possible values that users + may be counted in. Each detected value is added to a set of users who have + reported this information. This ensures that a user may only increment each + statistic once, even if they've reported several issues with the same hardware + and software configuration. If a single user has reported several issues with + *different* hardware and software configurations, then all configurations are + counted from this user. +- The dictionary is written to a JSON file, with the `set()` value replaced by + the number of users who have been detected to be using the hardware/software + in question. +- The resulting JSON file + the frontend is deployed to GitHub Pages using + GitHub Actions every day. + +[^1]: In rare scenarios, this can be inaccurate. In this case, the script errs + on the side of the most popular variant. For instance, the GeForce GTX 1060 + is considered to always have 6 GB of VRAM, even though it also exists in a + less popular 3 GB variant. See comments in [`build.py`](/build.py)'s + hardware detection routine for details. + +### Frontend + +- The frontend is a single [`index.html`](/index.html) page, plus the + third-party dependencies mentioned below. No frontend building is required. +- [Frappe Charts](https://frappe.io/charts) is used to display charts. +- [Ky](https://github.com/sindresorhus/ky) is used to make an HTTP request to the JSON file. +- [Water.css](https://watercss.kognise.dev/) is used for styling the page. + +## Development + +Follow these instructions to set up this site locally for development purposes: + +- Make sure you have [Python](https://python.org) 3.7 or later, pip and virtualenv. +- Create a virtualenv and activate it: `virtualenv venv && . venv/bin/activate`. +- Within the virtualenv, install dependencies by running `pip install -r requirements.txt`. +- Copy [`.env.example`](/.env.example) to `.env` and fill in the GitHub API key + with a personal access token. You can generate one + [here](https://github.com/settings/tokens) (it **must** have the `public_repo` scope). +- Run `python build.py` to fetch issue data from the GitHub API. +- Start a local web server in the root directory then browse `index.html`. + ## License Copyright © 2023-present Hugo Locurcio and contributors diff --git a/index.html b/index.html index 0d5d6d8..eccbe45 100644 --- a/index.html +++ b/index.html @@ -206,8 +206,8 @@ "dedicated_gcn2.0": "#991b1b", "dedicated_gcn1.0": "#7f1d1d", dedicated_vliw4: "#450a0a", - integrated_rdna3: "#92400e", - integrated_rdna2: "#78350f", + integrated_rdna3: "#92400e", + integrated_rdna2: "#78350f", "integrated_gcn5.0": "#451a03", // Intel GPU generation. @@ -273,12 +273,19 @@ function getRemappedString(label) { // Capitalize string (like_this => Like This) if not found in the remaps table. - // Replace "Dedicated" and "Integrated" with shorter forms if not using the remaps table (useful for NVIDIA GPUs). + // Replace "Dedicated" and "Integrated" with shorter forms if not using the remaps table + // (useful for NVIDIA GPUs). // Replace " Gb" for VRAM sizes. - return capitalizeStringRemaps[label] ?? label.replaceAll("_", " ").replace(/\b\w/g, l => l.toUpperCase()).replace("Dedicated", "Dedi.").replace("Integrated", "IGP").replace(" Gb", " GB").replace("Macos", "macOS").replace("Ios", "iOS"); + return capitalizeStringRemaps[label] ?? label.replaceAll("_", " ").replace(/\b\w/g, l => l.toUpperCase()) + .replace("Dedicated", "Dedi.") + .replace("Integrated", "IGP") + .replace(" Gb", " GB") + .replace("Macos", "macOS") + .replace("Ios", "iOS"); } function getChartColor(label) { + // Use a random color as a fallback if the color for the given label can't be found in the list. return chartColors[label] ?? '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6); } @@ -290,9 +297,14 @@ new frappe.Chart(id, { data: { labels: Object.keys(dataset).map(label => getRemappedString(label)), - datasets: [{ values: chartDatatype == ChartDatatype.INDIVIDUAL ? Object.values(dataset) : Object.values(dataset).map(subObject => Object.values(subObject).reduce(sum, 0)) }], + datasets: [{ + values: chartDatatype == ChartDatatype.INDIVIDUAL + ? Object.values(dataset) + : Object.values(dataset).map(subObject => Object.values(subObject).reduce(sum, 0)), + }], }, - height: 145, // Make charts slightly more compact (default height is 168 in our case). + // Make charts slightly more compact (default height is 168 in our case). + height: 145, type: "percentage", colors: Object.keys(dataset).map(label => getChartColor(label)), }); @@ -544,13 +556,19 @@ Scores are sourced from PassMark.
For reference, here are some example GPUs that roughly match each score threshold: