Showing preview only (456K chars total). Download the full file or copy to clipboard to get everything.
Repository: Cyclenerd/google-cloud-compute-machine-types
Branch: master
Commit: 6df0dc708acd
Files: 119
Total size: 426.3 KB
Directory structure:
gitextract_uvs6_j8g/
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── config.yml
│ │ └── feature_request.md
│ └── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build/
│ ├── 00_config.sh
│ ├── 01_create_database.sh
│ ├── 01_create_database.sql
│ ├── 02_get.sh
│ ├── 03_copy.pl
│ ├── 04_clean_up.sh
│ ├── 05_copy_disks.pl
│ ├── 05_copy_instances.pl
│ ├── 06_add_costs.pl
│ ├── 07_add.sh
│ ├── 08_cpu.pl
│ ├── 08_publicipranges.pl
│ ├── 08_publicipranges.sh
│ ├── 09_more.sh
│ ├── 10_export.sh
│ ├── 11_test.sh
│ ├── README.md
│ ├── app.psgi
│ ├── build.sh
│ ├── cpanfile
│ ├── site.pl
│ └── src/
│ ├── 404.tt2
│ ├── ads.txt
│ ├── amd.tt2
│ ├── arm.tt2
│ ├── comparison.tt2
│ ├── config.tt2
│ ├── disk.tt2
│ ├── diskpricing.tt2
│ ├── disks.js
│ ├── disks.tt2
│ ├── download.tt2
│ ├── favicon.tt2
│ ├── footer.tt2
│ ├── gcosts.tt2
│ ├── gpu.tt2
│ ├── grid.tt2
│ ├── hana.tt2
│ ├── header.tt2
│ ├── images.tt2
│ ├── img/
│ │ └── favicon/
│ │ ├── README.txt
│ │ └── site.webmanifest
│ ├── imprint.tt2
│ ├── index.tt2
│ ├── instance.tt2
│ ├── instance_in_region.json
│ ├── instance_in_region.tt2
│ ├── instances.tt2
│ ├── instances_header.tt2
│ ├── instances_tr.tt2
│ ├── intel.tt2
│ ├── macros.tt2
│ ├── main.js
│ ├── map.tt2
│ ├── meta.tt2
│ ├── platforms.tt2
│ ├── popin-min.js
│ ├── region.tt2
│ ├── regions.tt2
│ ├── regions_header.tt2
│ ├── robots.txt
│ ├── sap.tt2
│ ├── sitemap.tt2
│ └── vs.tt2
├── instances/
│ ├── README.md
│ ├── clean_up.sql
│ └── series/
│ ├── a2.sql
│ ├── a3.sql
│ ├── c2.sql
│ ├── c2d.sql
│ ├── c3.sql
│ ├── c3d.sql
│ ├── c4.sql
│ ├── c4a.sql
│ ├── c4d.sql
│ ├── cpu/
│ │ ├── README.md
│ │ ├── coremark.csv
│ │ ├── coremark.ods
│ │ ├── coremark.pl
│ │ ├── coremark.sql
│ │ └── frequency.sql
│ ├── e2.sql
│ ├── g2.sql
│ ├── gpu/
│ │ └── gpu_names.sql
│ ├── h3.sql
│ ├── m1.sql
│ ├── m2.sql
│ ├── m3.sql
│ ├── m4.sql
│ ├── n1.sql
│ ├── n2.sql
│ ├── n2d.sql
│ ├── n4.sql
│ ├── n4a.sql
│ ├── n4d.sql
│ ├── sap/
│ │ ├── hana.sql
│ │ └── sap.sql
│ ├── t2a.sql
│ ├── t2d.sql
│ └── z3.sql
└── regions/
├── README.md
├── carbon.csv
├── carbon.pl
├── carbon.sql
├── country.sql
├── extra.sql
├── regions.json
├── regions.pl
└── regions.sql
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/FUNDING.yml
================================================
github: Cyclenerd
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: 'Bug: Good title'
labels: 'bug'
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: Contact me on Mastodon
url: https://fosstodon.org/@cyclenerd
about: Feel free to follow me on Mastodon and send me a message
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: 'Feature request: Good title'
labels: 'enhancement'
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/PULL_REQUEST_TEMPLATE.md
================================================
First off, thanks for taking the time to contribute!
## Please Complete the Following
- [ ] I read `CONTRIBUTING.md`
- [ ] I used tabs to indent
- [ ] I have tested my change
## Notes
Feel free to put whatever you want here.
================================================
FILE: .gitignore
================================================
/site/**
/build/*.csv
/build/*.gz
/build/*.json
/build/*.yml
/build/*.conf
/build/*.db
/build/*.db-journal
/build/machine-types-regions.sql
/build/machine-types-regions.sql.gz
/build/publicipranges.json
/build/publicipaddresses.sql
.~lock*
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
nils [at] nkn-it (dot) de.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: CONTRIBUTING.md
================================================
# How to contribute
First off, thanks for taking the time to contribute!
## Submitting changes
Please send a GitHub Pull Request with a clear list of what you've done (read more about [pull requests](http://help.github.com/pull-requests/)).
Always write a clear log message for your commits. One-line messages are fine for small changes, but bigger changes should look like this:
```
$ git commit -m "A brief summary of the commit
>
> A paragraph describing what changed and its impact."
```
## Coding style
Start reading the code and you'll get the hang of it. It is optimized for readability:
* Please also update the documentation.
* Space before the opening curly of a multi-line BLOCK.
* No space before the semicolon.
* Space around most operators.
* No space between function name and its opening parenthesis.
* Line up corresponding things vertically, especially if it'd be too long to fit on one line anyway.
* Please use tabs to indent.
* Be nice.
One more thing:
* Keep it simple! 👍
Thanks! ❤️❤️❤️
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# Google Cloud Compute Comparison
[](#readme)
[](https://github.com/Cyclenerd/google-cloud-compute-machine-types/blob/master/LICENSE)
This Google Compute Engine machine type comparison [webapp](https://gcloud-compute.com/) helps to find the optimal GCE machine type or instance in the many Google Cloud Platform (GCP) regions. A lot of information has been collected from various Google Cloud websites and different sources.
## Instance Picker
[](https://gcloud-compute.com/)
## Comparison
[](https://gcloud-compute.com/comparison/e2-standard-4/vs/t2a-standard-4.html)
## 🖊️ Add, edit or change machine type information
The Google Compute Engine API is used to get all machine types in all regions and zones.
Additional information is read via SQL files during the build process.
Dive into the [build](./build/) folder to see how the data is retrieved, processed, and integrated.
Feel free to explore and contribute!
## ❤️ Contributing
Have a patch that will benefit this project?
Awesome! Follow these steps to have it accepted.
1. Please read [how to contribute](CONTRIBUTING.md).
1. Fork this Git repository and make your changes.
1. Create a Pull Request.
1. Incorporate review feedback to your changes.
1. Accepted!
## 📜 License
All files in this repository are under the [Apache License, Version 2.0](LICENSE) unless noted otherwise.
Portions of this webapp are modifications based on work created and shared by [Google](https://developers.google.com/readme/policies)
and used according to terms described in the [Creative Commons 4.0 Attribution License](https://creativecommons.org/licenses/by/4.0/).
Please note:
* No warranty
* No official Google product
================================================
FILE: build/00_config.sh
================================================
#!/usr/bin/env bash
DB='gce.db'
CSV_GCLOUD_MACHINE_TYPES="machinetypes.csv"
CSV_GCLOUD_ZONES="zones.csv"
CSV_GCLOUD_DISK_TYPES="disktypes.csv"
CSV_GCLOUD_IMAGES="images.csv"
CSV_EXPORT='machine-types-regions.csv'
SQL_EXPORT='machine-types-regions.sql'
================================================
FILE: build/01_create_database.sh
================================================
#!/usr/bin/env bash
set -e
#
# Create SQLite3 database for GCE machine type informations
#
source "00_config.sh"
sqlite3 "$DB" < "01_create_database.sql"
================================================
FILE: build/01_create_database.sql
================================================
/*
* Create SQLite3 database for GCE machine type informations
*/
DROP TABLE IF EXISTS "machinetypes";
CREATE TABLE "machinetypes" (
"name" TEXT NOT NULL DEFAULT '',
'description' TEXT NOT NULL DEFAULT '',
'location' TEXT NOT NULL DEFAULT '',
'region' TEXT NOT NULL DEFAULT '',
'zone' TEXT NOT NULL DEFAULT '',
'guestCpus' INT NOT NULL DEFAULT '0',
'isSharedCpu' TEXT NOT NULL DEFAULT 'false',
'memoryGB' REAL NOT NULL DEFAULT '0.0',
'guestAcceleratorCount' INT NOT NULL DEFAULT '0',
'guestAcceleratorType' TEXT NOT NULL DEFAULT '',
'maximumPersistentDisks' INT NOT NULL DEFAULT '0',
'maximumPersistentDisksSizeGb' INT NOT NULL DEFAULT '0',
PRIMARY KEY("name", "zone")
);
DROP TABLE IF EXISTS "zones";
CREATE TABLE "zones" (
"name" TEXT NOT NULL DEFAULT '',
'availableCpuPlatforms' TEXT NOT NULL DEFAULT '',
PRIMARY KEY("name")
);
DROP TABLE IF EXISTS "instances";
CREATE TABLE "instances" (
"name" TEXT NOT NULL DEFAULT '',
"series" TEXT DEFAULT 'TODO',
"family" TEXT DEFAULT 'TODO',
"description" TEXT DEFAULT '',
"location" TEXT NOT NULL DEFAULT '',
"region" TEXT NOT NULL DEFAULT '',
"regionLocation" TEXT NOT NULL DEFAULT '',
"regionLocationLong" TEXT NOT NULL DEFAULT '',
"regionLocationCountryCode" TEXT NOT NULL DEFAULT '',
"regionCfe" REAL DEFAULT '',
"regionCo2Kwh" REAL DEFAULT '',
"regionLowCo2" REAL DEFAULT '0.0',
"regionLat" REAL DEFAULT '0.0',
"regionLng" REAL DEFAULT '0.0',
"regionPublicIpv4Addr" REAL DEFAULT '0.0',
"zoneCount" REAL DEFAULT '0.0',
"zones" TEXT DEFAULT '',
"vCpus" REAL DEFAULT '0.0',
"sharedCpu" TEXT DEFAULT 'false',
"intel" REAL DEFAULT '0.0',
"amd" REAL DEFAULT '0.0',
"arm" REAL DEFAULT '0.0',
"cpuPlatformCount" REAL DEFAULT '0.0',
"cpuPlatform" TEXT DEFAULT '',
"cpuBaseClock" REAL DEFAULT '0.0',
"cpuTurboClock" REAL DEFAULT '0.0',
"cpuSingleMaxTurboClock" REAL DEFAULT '0.0',
"availableCpuPlatformCount" REAL DEFAULT '0.0',
"availableCpuPlatform" TEXT DEFAULT '',
"coremarkScore" REAL DEFAULT '',
"standardDeviation" REAL DEFAULT '',
"sampleCount" REAL DEFAULT '',
"memoryGB" REAL DEFAULT '0.0',
"acceleratorCount" REAL DEFAULT '0.0',
"acceleratorType" TEXT DEFAULT '',
"disks" REAL DEFAULT '0.0',
"disksSizeGb" REAL DEFAULT '0.0',
"localSsd" REAL DEFAULT '0.0',
"bandwidth" REAL DEFAULT '0.0',
"tier1" REAL DEFAULT '0.0',
"sap" REAL DEFAULT '0.0',
"saps" REAL DEFAULT '',
"hana" REAL DEFAULT '0.0',
"sud" REAL DEFAULT '0.0',
"spot" REAL DEFAULT '0.0',
"hour" REAL DEFAULT '0.0',
"hourSpot" REAL DEFAULT '0.0',
"month" REAL DEFAULT '0.0',
"month1yCud" REAL DEFAULT '0.0',
"month3yCud" REAL DEFAULT '0.0',
"monthSpot" REAL DEFAULT '0.0',
"monthSles" REAL DEFAULT '0.0',
"monthSlesSap" REAL DEFAULT '0.0',
"monthSlesSap1yCud" REAL DEFAULT '0.0',
"monthSlesSap3yCud" REAL DEFAULT '0.0',
"monthRhel" REAL DEFAULT '0.0',
"monthRhel1yCud" REAL DEFAULT '0.0',
"monthRhel3yCud" REAL DEFAULT '0.0',
"monthRhelSap" REAL DEFAULT '0.0',
"monthRhelSap1yCud" REAL DEFAULT '0.0',
"monthRhelSap3yCud" REAL DEFAULT '0.0',
"monthWindows" REAL DEFAULT '0.0',
PRIMARY KEY("name", "region")
);
DROP TABLE IF EXISTS "disktypes";
CREATE TABLE "disktypes" (
"name" TEXT NOT NULL DEFAULT '',
'description' TEXT NOT NULL DEFAULT '',
'location' TEXT NOT NULL DEFAULT '',
'region' TEXT NOT NULL DEFAULT '',
'zone' TEXT NOT NULL DEFAULT '',
PRIMARY KEY("name", "zone")
);
DROP TABLE IF EXISTS "disks";
CREATE TABLE "disks" (
"name" TEXT NOT NULL DEFAULT '',
"description" TEXT DEFAULT '',
"location" TEXT NOT NULL DEFAULT '',
"region" TEXT NOT NULL DEFAULT '',
"regionLocation" TEXT NOT NULL DEFAULT '',
"zoneCount" REAL DEFAULT '0.0',
"zones" TEXT DEFAULT '',
"monthGb" REAL DEFAULT '0.0',
PRIMARY KEY("name", "region")
);
DROP TABLE IF EXISTS "images";
CREATE TABLE "images" (
"name" TEXT NOT NULL DEFAULT '',
"description" TEXT DEFAULT '',
"diskSizeGb" REAL DEFAULT '0.0',
"project" TEXT NOT NULL DEFAULT '',
"family" TEXT NOT NULL DEFAULT '',
"architecture" TEXT NOT NULL DEFAULT '',
"creation" REAL DEFAULT '0.0',
PRIMARY KEY("name", "project", "family")
);
/* Index */
CREATE INDEX IF NOT EXISTS "instances-name-index" ON instances(name COLLATE NOCASE);
CREATE INDEX IF NOT EXISTS "instances-region-index" ON instances(region COLLATE NOCASE);
CREATE INDEX IF NOT EXISTS "instances-region-name-index" ON instances(region, name COLLATE NOCASE);
CREATE INDEX IF NOT EXISTS "instances-region-hana-index" ON instances(region, hana);
CREATE INDEX IF NOT EXISTS "instances-region-sap-index" ON instances(region, sap);
CREATE INDEX IF NOT EXISTS "instances-region-series-index" ON instances(region, series COLLATE NOCASE);
CREATE INDEX IF NOT EXISTS "disks-name-index" ON disks(name COLLATE NOCASE);
CREATE INDEX IF NOT EXISTS "disks-region-index" ON disks(region COLLATE NOCASE);
================================================
FILE: build/02_get.sh
================================================
#!/usr/bin/env bash
set -e
#
# Export all Google Compute Engine machine types and zones via the
# Google Compute Engine API and create CSV file
#
source "00_config.sh"
echo "Download pricing..."
curl -OL "https://github.com/Cyclenerd/google-cloud-pricing-cost-calculator/raw/master/pricing.yml"
echo
# Create CSV file with machine types
echo "Executing: 'gcloud compute machine-types list', please wait..."
printf "%s;" \
"name" \
"description" \
"zone" \
"guestCpus" \
"isSharedCpu" \
"memoryGB" \
"guestAcceleratorCount" \
"guestAcceleratorType" \
"maximumPersistentDisks" \
"maximumPersistentDisksSizeGb" \
"deprecated" > "$CSV_GCLOUD_MACHINE_TYPES"
echo "" >> "$CSV_GCLOUD_MACHINE_TYPES"
gcloud compute machine-types list \
--quiet \
--filter="ZONE:-" \
--format="csv[no-heading,separator=';']( \
name, \
description, \
zone, \
guestCpus, \
isSharedCpu, \
MEMORY_GB, \
accelerators.guestAcceleratorCount, \
accelerators.guestAcceleratorType, \
maximumPersistentDisks, \
maximumPersistentDisksSizeGb, \
deprecated.state)" >> "$CSV_GCLOUD_MACHINE_TYPES"
# Create CSV file with zones and available CPU platforms
echo "Executing: 'gcloud compute zones list', please wait..."
printf "%s;" \
"name" \
"availableCpuPlatforms" > "$CSV_GCLOUD_ZONES"
echo "" >> "$CSV_GCLOUD_ZONES"
gcloud compute zones list \
--quiet \
--format="csv[no-heading,separator=';'](name, availableCpuPlatforms.list())" >> "$CSV_GCLOUD_ZONES"
# Fix Google Axion CPU platform name:
# Parse the CSV file line by line. If 'Google Axion' is in line and 'Google Axion_' remove 'Google Axion_'.
perl -i -pe "s/Google Axion_,//g if /Google Axion/" "$CSV_GCLOUD_ZONES"
perl -i -pe "s/Google Axion_//g if /Google Axion/" "$CSV_GCLOUD_ZONES"
# Create CSV file with disk types
echo "Executing: 'gcloud compute disk-types list', please wait..."
printf "%s;" \
"name" \
"zone" \
"description" > "$CSV_GCLOUD_DISK_TYPES"
echo "" >> "$CSV_GCLOUD_DISK_TYPES"
gcloud compute disk-types list \
--quiet \
--filter="ZONE:-" \
--format="csv[no-heading,separator=';']( \
name, \
zone, \
description)" >> "$CSV_GCLOUD_DISK_TYPES"
# Create CSV files with images
echo "Executing: 'gcloud compute images list', please wait..."
# Standard images
echo "name;description;diskSizeGb;project;family;architecture;creation;deprecated;status" > "$CSV_GCLOUD_IMAGES"
gcloud compute images list \
--quiet \
--format="csv[no-heading,separator=';'](NAME,description,diskSizeGb,PROJECT,FAMILY,architecture,creationTimestamp,DEPRECATED,STATUS)" >> "$CSV_GCLOUD_IMAGES"
# Community images
# https://cloud.google.com/compute/docs/images#almalinux
gcloud compute images list \
--project almalinux-cloud \
--no-standard-images \
--quiet \
--format="csv[no-heading,separator=';'](NAME,description,diskSizeGb,PROJECT,FAMILY,architecture,creationTimestamp,DEPRECATED,STATUS)" >> "$CSV_GCLOUD_IMAGES"
# https://cloud.google.com/compute/docs/images#freebsd
gcloud compute images list \
--project freebsd-org-cloud-dev \
--no-standard-images \
--quiet \
--format="csv[no-heading,separator=';'](NAME,description,diskSizeGb,PROJECT,FAMILY,architecture,creationTimestamp,DEPRECATED,STATUS)" >> "$CSV_GCLOUD_IMAGES"
# Deep Learning on Linux images
gcloud compute images list \
--project ml-images \
--filter="creationTimestamp > -P1Y" \
--no-standard-images \
--quiet \
--format="csv[no-heading,separator=';'](NAME,description,diskSizeGb,PROJECT,FAMILY,architecture,creationTimestamp,DEPRECATED,STATUS)" >> "$CSV_GCLOUD_IMAGES"
# https://cloud.google.com/deep-learning-vm/docs/images#listing-versions
gcloud compute images list \
--project deeplearning-platform-release \
--filter="creationTimestamp > -P1Y" \
--no-standard-images \
--quiet \
--format="csv[no-heading,separator=';'](NAME,description,diskSizeGb,PROJECT,FAMILY,architecture,creationTimestamp,DEPRECATED,STATUS)" >> "$CSV_GCLOUD_IMAGES"
# High Performance Computing (HPC)
gcloud compute images list \
--project cloud-hpc-image-public \
--filter="creationTimestamp > -P1Y" \
--no-standard-images \
--quiet \
--format="csv[no-heading,separator=';'](NAME,description,diskSizeGb,PROJECT,FAMILY,architecture,creationTimestamp,DEPRECATED,STATUS)" >> "$CSV_GCLOUD_IMAGES"
echo "DONE"
================================================
FILE: build/03_copy.pl
================================================
#!/usr/bin/env perl
# Copyright 2022 Nils Knieling. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copy machine types from CSV export to SQLite database
#
use utf8;
binmode(STDOUT, ':encoding(utf8)');
use strict;
use DBI;
# CSV files without .csv
my $csv_gcloud_machine_types = 'machinetypes';
my $csv_gcloud_zones = 'zones';
my $csv_gcloud_disk_types = 'disktypes';
my $csv_gcloud_images = 'images';
my $csv_gcloud_community_images = 'imagescommunity';
my $csv_gcloud_deeplearning_images = 'imagesdeeplearning';
# SQLite database file
my $db_file = 'gce.db';
# Open CSV
my $csv = DBI->connect("dbi:CSV:", undef, undef, {
f_ext => ".csv/r",
csv_sep_char => ";",
csv_class => "Text::CSV_XS",
RaiseError => 1,
}) or die "ERROR: Cannot connect $DBI::errstr\n";
# Open DB
my $db = DBI->connect("dbi:SQLite:dbname=$db_file","","") or die "ERROR: Cannot connect $DBI::errstr\n";
###############################################################################
# MACHINE TYPES
###############################################################################
print "Machine types\n";
$db->do("DELETE FROM machinetypes") or die "ERROR: Cannot delete table $DBI::errstr\n";
# Select machine types from CSV
my $select = qq ~
SELECT
name, description, zone,
guestCpus, isSharedCpu,
memoryGB,
guestAcceleratorCount, guestAcceleratorType,
maximumPersistentDisks, maximumPersistentDisksSizeGb,
deprecated
FROM $csv_gcloud_machine_types
~;
my $sth = $csv->prepare($select);
$sth->execute;
$sth->bind_columns (\my (
$name, $description, $zone,
$guestCpus, $isSharedCpu,
$memoryGB,
$guestAcceleratorCount, $guestAcceleratorType,
$maximumPersistentDisks, $maximumPersistentDisksSizeGb,
$deprecated
));
# Create values for insert
my @values = ();
while ($sth->fetch) {
next if ($deprecated); # Skip deprecated machine-types
print "$name, $zone\n";
# Location and region
my @zone_parts = split(/-/, $zone);
my $location = "$zone_parts[0]";
my $region = "$zone_parts[0]-$zone_parts[1]";
$isSharedCpu = lc($isSharedCpu);
# Create value for SQL INSERT
my $value = qq ~
(
'$name', '$description', '$location', '$region', '$zone',
'$guestCpus', '$isSharedCpu',
'$memoryGB',
'$guestAcceleratorCount', '$guestAcceleratorType',
'$maximumPersistentDisks', '$maximumPersistentDisksSizeGb'
)
~;
$value =~ s/\t//g;
push(@values, $value);
}
$sth->finish;
# Insert machine types to database table
my $insert = qq ~
INSERT INTO machinetypes (
'name', 'description', 'location', 'region', 'zone',
'guestCpus', 'isSharedCpu',
'memoryGB',
'guestAcceleratorCount', 'guestAcceleratorType',
'maximumPersistentDisks', 'maximumPersistentDisksSizeGb'
) VALUES
~;
$insert .= join(",", @values);
$insert .= ";\n";
$db->do($insert) or die "ERROR: Cannot insert machine types $DBI::errstr\n";
###############################################################################
# ZONES
###############################################################################
print "Zones\n";
$db->do("DELETE FROM zones") or die "ERROR: Cannot delete table $DBI::errstr\n";
# Select machine types from CSV
my $select_zones = "SELECT name, availableCpuPlatforms FROM $csv_gcloud_zones";
$sth = $csv->prepare($select_zones);
$sth->execute;
$sth->bind_columns (\my ($name, $availableCpuPlatforms));
# Create values for insert
my @zones = ();
while ($sth->fetch) {
print "$name\n";
# Create value for SQL INSERT
my $zone = "('$name', '$availableCpuPlatforms')";
push(@zones, $zone);
}
$sth->finish;
my $insert_zones = "INSERT INTO zones ('name', 'availableCpuPlatforms') VALUES";
$insert_zones .= join(",", @zones);
$insert_zones .= ";\n";
$db->do($insert_zones) or die "ERROR: Cannot insert zones $DBI::errstr\n";
###############################################################################
# DISK TYPES
###############################################################################
print "Disk types\n";
$db->do("DELETE FROM disktypes") or die "ERROR: Cannot delete table $DBI::errstr\n";
# Select disk types from CSV
my $select_disks = "SELECT name, description, zone FROM $csv_gcloud_disk_types";
$sth = $csv->prepare($select_disks);
$sth->execute;
$sth->bind_columns (\my ($name, $description, $zone));
# Create values for insert
my @disks = ();
while ($sth->fetch) {
print "$name, $zone\n";
# Location and region
my @zone_parts = split(/-/, $zone);
my $location = "$zone_parts[0]";
my $region = "$zone_parts[0]-$zone_parts[1]";
# Create value for SQL INSERT
my $value = "('$name', '$description', '$location', '$region', '$zone')";
push(@disks, $value);
}
$sth->finish;
# Insert machine types to database table
my $insert_disks = qq ~
INSERT INTO disktypes (
'name',
'description',
'location',
'region',
'zone'
) VALUES
~;
$insert_disks .= join(",", @disks);
$insert_disks .= ";\n";
$db->do($insert_disks) or die "ERROR: Cannot insert disk types $DBI::errstr\n";
###############################################################################
# IMAGES
###############################################################################
print "Images\n";
$db->do("DELETE FROM images") or die "ERROR: Cannot delete table $DBI::errstr\n";
my $insert_images = qq ~
REPLACE INTO images (
'name',
'description',
'diskSizeGb',
'project',
'family',
'architecture',
'creation'
) VALUES
~;
my $select_images = "SELECT name, description, diskSizeGb, project, family, architecture, creation FROM $csv_gcloud_images WHERE status LIKE 'READY'";
$sth = $csv->prepare($select_images);
$sth->execute;
$sth->bind_columns (\my ($name, $description, $diskSizeGb, $project, $family, $architecture, $creation));
while ($sth->fetch) {
print "$project, $family, $name\n";
my $value = "$insert_images ('$name', '$description', '$diskSizeGb', '$project', '$family', '$architecture', '$creation')";
$db->do($value) or die "ERROR: Cannot insert images $DBI::errstr\n";
}
$sth->finish;
print "DONE\n";
================================================
FILE: build/04_clean_up.sh
================================================
#!/usr/bin/env bash
set -e
#
# Clean up (Remove disconnected data centers...)
#
source "00_config.sh"
sqlite3 "$DB" < "../instances/clean_up.sql"
================================================
FILE: build/05_copy_disks.pl
================================================
#!/usr/bin/env perl
# Copyright 2022 Nils Knieling. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copy disk types per region to disks table
#
use utf8;
binmode(STDOUT, ':encoding(utf8)');
use strict;
use DBI;
my $db_file = 'gce.db';
# Open DB
my $db = DBI->connect("dbi:SQLite:dbname=$db_file","","") or die "ERROR: Cannot connect $DBI::errstr\n";
###############################################################################
# Copy DISK TYPES to DISKS
###############################################################################
$db->do("DELETE FROM disks") or die "ERROR: Cannot delete table $DBI::errstr\n";
# Select 'disktypes'
my $select = qq ~
SELECT
name, description, location, region,
(SELECT COUNT(zone) FROM disktypes WHERE name LIKE D.name AND region LIKE D.region) AS zoneCount,
(SELECT GROUP_CONCAT(zone) FROM disktypes WHERE name LIKE D.name AND region LIKE D.region ORDER BY zone) AS zones
FROM disktypes D
GROUP BY name, region;
~;
my $sth = $db->prepare($select);
$sth->execute;
$sth->bind_columns ( \my (
$name, $description, $location, $region,
$zoneCount,
$zones
));
# Insert disk type per region to disks table
my @values = ();
while ($sth->fetch) {
print "$name, $region\n";
# Sort zones
my @zones_unsorted = split(',', $zones);
$zones = join(', ', sort @zones_unsorted);
# Create value for SQL INSERT
my $value = "('$name', '$description', '$location', '$region', '$zoneCount', '$zones')";
push(@values, $value);
}
$sth->finish;
my $insert = qq ~
INSERT INTO disks (
'name',
'description',
'location',
'region',
'zoneCount',
'zones'
) VALUES
~;
$insert .= join(",", @values);
$insert .= ";\n";
$db->do($insert) or die "ERROR: Cannot insert $DBI::errstr\n";
print "DONE\n";
================================================
FILE: build/05_copy_instances.pl
================================================
#!/usr/bin/env perl
# Copyright 2022 Nils Knieling. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Copy machine types per region to instances table
#
use utf8;
binmode(STDOUT, ':encoding(utf8)');
use strict;
use DBI;
my $db_file = 'gce.db';
# Open DB
my $db = DBI->connect("dbi:SQLite:dbname=$db_file","","") or die "ERROR: Cannot connect $DBI::errstr\n";
###############################################################################
# Copy MACHINE TYPES to INSTANCES
###############################################################################
$db->do("DELETE FROM instances") or die "ERROR: Cannot delete table $DBI::errstr\n";
# Select 'machinetypes'
my $select = qq ~
SELECT
name, description, location, region,
(SELECT COUNT(zone) FROM machinetypes WHERE name LIKE M.name AND region LIKE M.region) AS zoneCount,
(SELECT GROUP_CONCAT(zone) FROM machinetypes WHERE name LIKE M.name AND region LIKE M.region ORDER BY zone) AS zones,
guestCpus, isSharedCpu,
memoryGB,
guestAcceleratorCount, guestAcceleratorType,
maximumPersistentDisks, maximumPersistentDisksSizeGb
FROM machinetypes M
GROUP BY name, region;
~;
my $sth = $db->prepare($select);
$sth->execute;
$sth->bind_columns ( \my (
$name, $description, $location, $region,
$zoneCount,
$zones,
$guestCpus, $isSharedCpu,
$memoryGB,
$guestAcceleratorCount, $guestAcceleratorType,
$maximumPersistentDisks, $maximumPersistentDisksSizeGb
));
# Insert machine type per region to instances table
my @values = ();
while ($sth->fetch) {
print "$name, $region\n";
# Shared CPU
if (lc($isSharedCpu) eq 'true') {
$isSharedCpu = '1';
} else {
$isSharedCpu = '0'
}
# Sort zones
my @zones_unsorted = split(',', $zones);
$zones = join(', ', sort @zones_unsorted);
# Create value for SQL INSERT
my $value = qq ~
(
'$name', '$description', '$location', '$region', '$zoneCount', '$zones',
'$guestCpus', '$isSharedCpu',
'$memoryGB',
'$guestAcceleratorCount', '$guestAcceleratorType',
'$maximumPersistentDisks', '$maximumPersistentDisksSizeGb'
)
~;
$value =~ s/\t//g;
push(@values, $value);
}
$sth->finish;
my $insert = qq ~
INSERT INTO instances (
'name', 'description', 'location', 'region', 'zoneCount', 'zones',
'vCpus', 'sharedCpu',
'memoryGB',
'acceleratorCount', 'acceleratorType',
'disks', 'disksSizeGb'
) VALUES
~;
$insert .= join(",", @values);
$insert .= ";\n";
$db->do($insert) or die "ERROR: Cannot insert $DBI::errstr\n";
print "DONE\n";
================================================
FILE: build/06_add_costs.pl
================================================
#!/usr/bin/env perl
# Copyright 2022-2024 Nils Knieling. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Add costs for machine types in region from pricing (https://github.com/Cyclenerd/google-cloud-pricing-cost-calculator)
#
use utf8;
binmode(STDOUT, ':encoding(utf8)');
use strict;
use DBI;
use YAML::XS qw(LoadFile);
use App::Options (
option => {
pricing => {
required => 1,
default => 'pricing.yml',
description => "YAML file with GCP pricing information"
},
},
);
# Open DB
my $db_file = 'gce.db';
my $db = DBI->connect("dbi:SQLite:dbname=$db_file","","") or die "ERROR: Cannot connect $DBI::errstr\n";
# Load YAML file with GCP information
my $pricing_file = $App::options{pricing};
unless (-r "$pricing_file") { # read
die "ERROR: Cannot open YAML file '$pricing_file' for GCP information import!\n";
}
my $gcp = LoadFile("$pricing_file");
###############################################################################
# INSTANCES
###############################################################################
print "\nInstances\n";
foreach my $machine (keys %{ $gcp->{'compute'}->{'instance'} }) {
print "$machine\n";
# OS license per month
my $sles = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'sles'}->{'month'};
my $slesSap = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'sles-sap'}->{'month'};
my $slesSap1y = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'sles-sap'}->{'month_1y'} || $slesSap;
my $slesSap3y = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'sles-sap'}->{'month_3y'} || $slesSap;
my $rhel = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'rhel'}->{'month'};
my $rhel1y = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'rhel'}->{'month_1y'} || $rhel;
my $rhel3y = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'rhel'}->{'month_3y'} || $rhel;
my $rhelSap = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'rhel-sap'}->{'month'};
my $rhelSap1y = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'rhel-sap'}->{'month_1y'} || $rhelSap;
my $rhelSap3y = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'rhel-sap'}->{'month_3y'} || $rhelSap;
my $windows = $gcp->{'compute'}->{'license'}->{$machine}->{'cost'}->{'windows'}->{'month'};
foreach my $region (keys %{ $gcp->{'compute'}->{'instance'}->{$machine}->{'cost'} }) {
print "\t$region\n";
# vCPU and memory in region per hour and month
my $hour = $gcp->{'compute'}->{'instance'}->{$machine}->{'cost'}->{$region}->{'hour'} || '0.0';
my $hour_spot = $gcp->{'compute'}->{'instance'}->{$machine}->{'cost'}->{$region}->{'hour_spot'} || $hour;
my $month = $gcp->{'compute'}->{'instance'}->{$machine}->{'cost'}->{$region}->{'month'} || '0.0';
my $month_1y = $gcp->{'compute'}->{'instance'}->{$machine}->{'cost'}->{$region}->{'month_1y'} || $month;
my $month_3y = $gcp->{'compute'}->{'instance'}->{$machine}->{'cost'}->{$region}->{'month_3y'} || $month;
my $month_spot = $gcp->{'compute'}->{'instance'}->{$machine}->{'cost'}->{$region}->{'month_spot'} || $month;
my $update = qq ~
UPDATE instances SET
hour = '$hour',
hourSpot = '$hour_spot',
month = '$month',
month1yCud = '$month_1y',
month3yCud = '$month_3y',
monthSpot = '$month_spot',
monthSles = '$sles',
monthSlesSap = '$slesSap',
monthSlesSap1yCud = '$slesSap1y',
monthSlesSap3yCud = '$slesSap3y',
monthRhel = '$rhel',
monthRhel1yCud = '$rhel1y',
monthRhel3yCud = '$rhel3y',
monthRhelSap = '$rhelSap',
monthRhelSap1yCud = '$rhelSap1y',
monthRhelSap3yCud = '$rhelSap3y',
monthWindows = '$windows'
WHERE name LIKE '$machine' AND region LIKE '$region'
~;
$db->do($update) or die "ERROR: Cannot update $DBI::errstr\n";
}
}
###############################################################################
# DISKS
###############################################################################
print "\nDisks\n";
# gcosts -> gcloud disk-types name mapping
my %storage_types = (
'local' => 'local-ssd',
'balanced' => 'pd-balanced',
'extreme' => 'pd-extreme',
'ssd' => 'pd-ssd',
'hdd' => 'pd-standard',
'hdd' => 'pd-standard',
'hyperdisk-extreme' => 'hyperdisk-extreme',
);
foreach my $storage_type (keys %storage_types) {
my $disk_type = $storage_types{$storage_type};
print "$storage_type [$disk_type]\n";
foreach my $region (keys %{ $gcp->{'compute'}->{'storage'}->{$storage_type}->{'cost'} }) {
print "\t$region\n";
my $month = $gcp->{'compute'}->{'storage'}->{$storage_type}->{'cost'}->{$region}->{'month'};
my $update = "UPDATE disks SET monthGb = '$month' WHERE name LIKE '$disk_type' AND region LIKE '$region'";
$db->do($update) or die "ERROR: Cannot update $DBI::errstr\n";
}
}
###############################################################################
# LOCATION NAME
###############################################################################
print "\nRegion Locations\n";
# Update region location
foreach my $region (keys %{ $gcp->{'region'} }) {
my $regionLocation = $gcp->{'region'}->{$region}->{'location'};
print "$region : $regionLocation\n";
$db->do("UPDATE instances SET regionLocation = '$regionLocation', regionLocationLong = '$regionLocation' WHERE region LIKE '$region'") or die "ERROR: Cannot update $DBI::errstr\n";
$db->do("UPDATE disks SET regionLocation = '$regionLocation' WHERE region LIKE '$region'") or die "ERROR: Cannot update $DBI::errstr\n";
}
###############################################################################
# TEST
###############################################################################
print "\nTest\n";
# Check regions without location
my $sth = $db->prepare("SELECT region FROM instances WHERE regionLocation LIKE '' GROUP BY region");
$sth->execute;
$sth->bind_columns (\my ($region));
while ($sth->fetch) {
print "WARNING: Location of region '$region' missing!\n";
my $deleteLocation = "DELETE FROM instances WHERE region LIKE '$region'";
$db->do($deleteLocation) or die "ERROR: Cannot delete instances in unknown location $DBI::errstr\n";
}
# Check disks without price
$sth = $db->prepare("SELECT name, region FROM disks WHERE monthGb <= 0");
$sth->execute;
$sth->bind_columns (\my ($name, $region));
while ($sth->fetch) {
print "WARNING: Costs per month missing for disk type '$name' in region '$region'.\n";
}
# Chech instances without price
$sth = $db->prepare("SELECT name, region FROM instances WHERE hour <= 0");
$sth->execute;
$sth->bind_columns (\my ($name, $region));
while ($sth->fetch) {
print "WARNING: Costs per hour missing for machine type '$name' in region '$region'.\n";
my $deleteInstance = "DELETE FROM instances WHERE name LIKE '$name' AND region LIKE '$region'";
$db->do($deleteInstance) or die "ERROR: Cannot delete instance without price $DBI::errstr\n";
}
print "DONE\n";
================================================
FILE: build/07_add.sh
================================================
#!/usr/bin/env bash
set -e
#
# Add additional machine type and region informations
#
source "00_config.sh"
for MY_SERIES in ../instances/series/*.sql; do
echo "$MY_SERIES"
sqlite3 "$DB" < "$MY_SERIES"
done
echo "Add carbon data across GCP regions"
sqlite3 "$DB" < ../regions/carbon.sql
echo "Add long location name, latitude and longitude of GCP regions"
sqlite3 "$DB" < ../regions/regions.sql
echo "Add extra data for GCP regions"
sqlite3 "$DB" < ../regions/extra.sql
echo "Add country names of GCP regions"
sqlite3 "$DB" < ../regions/country.sql
================================================
FILE: build/08_cpu.pl
================================================
#!/usr/bin/env perl
# Copyright 2022 Nils Knieling. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Check available CPU platforms per instance in region and update machine type
#
use utf8;
binmode(STDOUT, ':encoding(utf8)');
use strict;
use DBI;
use Data::Dumper;
my $db_file = 'gce.db';
# Open DB
my $db = DBI->connect("dbi:SQLite:dbname=$db_file","","") or die "ERROR: Cannot connect $DBI::errstr\n";
print "\nZones\n";
my $select_zones = "SELECT name, availableCpuPlatforms FROM zones ORDER BY name";
my $sth = $db->prepare($select_zones);
$sth->execute;
$sth->bind_columns ( \my ($zone, $availableCpuPlatforms) );
my $cpuPlatforms = {}; # all CPU platforms
my $availableCpuPlatformsInRegion = {}; # available CPU platforms in region
while ($sth->fetch) {
print "$zone\n";
my @zone_parts = split(/-/, $zone);
my $location = "$zone_parts[0]";
my $region = "$zone_parts[0]-$zone_parts[1]";
# Store CPU platform in Perl Hash reference
foreach my $cpu (split(',', $availableCpuPlatforms)) {
$availableCpuPlatformsInRegion->{"$region"}->{"$cpu"} = '1';
$cpuPlatforms->{"$cpu"} = '1';
}
}
print "\nMachine types\n";
my $select_instances = "SELECT name, region, cpuPlatform FROM instances";
my $sth = $db->prepare($select_instances);
$sth->execute;
$sth->bind_columns ( \my ($name, $region, $cpuPlatform) );
my %unknown_cpuPlatform = ();
while ($sth->fetch) {
print "$name, $region\n";
my @cpuPlatformsInRegion = (); # available CPU platforms for machine type in the region, cross-checked with the available CPU platforms in the zones.
my @cpuPlatformsForInstance = (); # CPU platforms for machine type
foreach my $instance_cpuPlatform (sort split(',', $cpuPlatform)) {
print "\t$instance_cpuPlatform";
# Check if the CPU platform of the instance is known
my $found = 0;
foreach my $cpu (keys %{$cpuPlatforms}) {
if ($cpu =~ m/$instance_cpuPlatform/i) {
$found = '1';
push (@cpuPlatformsForInstance, $cpu); # Store longer name
}
}
if ($found) {
print " [found]";
# Check if CPU platform for this machine type is available in the region
foreach my $cpu (keys %{$availableCpuPlatformsInRegion->{"$region"}}) {
if ($cpu =~ m/$instance_cpuPlatform/i) {
print " [available]";
push (@cpuPlatformsInRegion, $cpu);
}
}
} else {
print " [unknown]";
$unknown_cpuPlatform{"$instance_cpuPlatform"} = '1';
}
print "\n";
}
# CPU platform for machine type
my $update_cpuPlatformCount = scalar @cpuPlatformsForInstance;
my $update_cpuPlatform = join(', ', sort @cpuPlatformsForInstance);
# CPU platform for machine type and available in region
my $update_availableCpuPlatformCount = scalar @cpuPlatformsInRegion;
my $update_availableCpuPlatform = join(', ', sort @cpuPlatformsInRegion);
# Set Intel and AMD
my $intel = '0';
$intel = '1' if ($update_availableCpuPlatform =~ m/intel/i );
my $amd = '0';
$amd = '1' if ($update_availableCpuPlatform =~ m/amd/i );
my $arm = '0';
$arm = '1' if ($update_availableCpuPlatform =~ m/ampere/i );
$arm = '1' if ($update_availableCpuPlatform =~ m/axion/i );
my $update = qq ~
UPDATE instances
SET
intel = '$intel',
amd = '$amd',
arm = '$arm',
cpuPlatformCount = '$update_cpuPlatformCount', cpuPlatform = '$update_cpuPlatform',
availableCpuPlatformCount = '$update_availableCpuPlatformCount', availableCpuPlatform = '$update_availableCpuPlatform'
WHERE name LIKE '$name'
AND region LIKE '$region'
~;
$db->do($update) or die "ERROR: Cannot update available CPU platform for instance in region $DBI::errstr\n";
}
if (keys %unknown_cpuPlatform) {
print "Unknown CPU platforms:\n";
foreach my $cpu (keys %unknown_cpuPlatform) {
print "\t $cpu\n";
}
die "Please check and fix!\n";
}
print "\nClean up unavailable CPU platforms\n";
my $select_not_available = "SELECT name, region FROM instances WHERE availableCpuPlatformCount == '0'";
my $sth = $db->prepare($select_not_available);
$sth->execute;
$sth->bind_columns ( \my ($name, $region) );
my $unavailable = 0;
while ($sth->fetch) {
print "$name, $region\n";
$unavailable++;
}
$db->do("DELETE FROM instances WHERE availableCpuPlatformCount == '0'") or die "ERROR: Cannot clean up unavailable CPU platforms $DBI::errstr\n";
if ($unavailable) {
print "Unavailable CPU platforms for machine type in region: $unavailable\n";
}
print "DONE\n";
================================================
FILE: build/08_publicipranges.pl
================================================
#!/usr/bin/env perl
# Copyright 2022 Nils Knieling. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Calculate public IP addresses
# Thank you PatMyron: https://github.com/PatMyron/cloud/issues/11#issuecomment-922591282
#
use utf8;
binmode(STDOUT, ':encoding(utf8)');
use strict;
use JSON::XS;
open(FH, "publicipranges.json") or die "JSON file 'publicipranges.json' can't be opened";
my $json = "";
while(<FH>){
$json .= $_;
}
close(FH);
my $publicipranges = JSON::XS->new->utf8->decode($json);
my %regions;
my $total = "0";
foreach my $prefix (sort @{$publicipranges->{'prefixes'}}) {
my $name = $prefix->{'scope'};
if ($prefix->{'ipv4Prefix'} =~ /\/(\d+)$/) {
my $mask = $1;
my $ipv4 = 2**(32-$mask);
$regions{$name} += $ipv4;
$total += $ipv4;
}
}
foreach my $region (sort keys %regions) {
my $ipv4 = $regions{$region} || "0.0";
print "UPDATE instances SET regionPublicIpv4Addr = '$ipv4' WHERE region LIKE '$region';\n";
}
================================================
FILE: build/08_publicipranges.sh
================================================
#!/usr/bin/env bash
set -e
#
# Add number of public IP addresses for each GCP region
#
source "00_config.sh"
echo "Get public IP ranges"
curl -o "publicipranges.json" "https://www.gstatic.com/ipranges/cloud.json"
echo "Calculate public IP addresses"
perl "08_publicipranges.pl" > "publicipaddresses.sql"
echo "Add number of public IP addresses for each GCP region"
sqlite3 "$DB" < "publicipaddresses.sql"
================================================
FILE: build/09_more.sh
================================================
#!/usr/bin/env bash
set -e
#
# Add more machine type informations
#
source "00_config.sh"
echo "Frequency (GHz)"
sqlite3 "$DB" < "../instances/series/cpu/frequency.sql"
echo "EEMBC CoreMark Benchmark"
sqlite3 "$DB" < "../instances/series/cpu/coremark.sql"
echo "GPU Type Names"
sqlite3 "$DB" < "../instances/series/gpu/gpu_names.sql"
echo "SAP certified machine types"
sqlite3 "$DB" < "../instances/series/sap/sap.sql"
echo "SAP HANA certified machine types"
sqlite3 "$DB" < "../instances/series/sap/hana.sql"
================================================
FILE: build/10_export.sh
================================================
#!/usr/bin/env bash
set -e
#
# Export CSV and SQL file
#
source "00_config.sh"
echo "» SQL Export"
{
echo 'DROP TABLE IF EXISTS "instances";'
sqlite3 "$DB" '.dump instances'
echo 'DROP TABLE IF EXISTS "disks";'
sqlite3 "$DB" '.dump disks'
echo 'DROP TABLE IF EXISTS "images";'
sqlite3 "$DB" '.dump images'
} > "$SQL_EXPORT"
gzip -fk "$SQL_EXPORT"
echo "» CSV Export"
sqlite3 \
-header \
-csv "$DB" "SELECT * FROM instances ORDER BY region, name;" > "$CSV_EXPORT"
================================================
FILE: build/11_test.sh
================================================
#!/usr/bin/env bash
set -e
#
# Test
#
source "00_config.sh"
# Check TODOs
if grep 'TODO' < "$CSV_EXPORT"; then
echo "ERROR: There are still TODOs"
exit 9
fi
# Check costs
# n2-standard-8 in europe-west4 with SUD : 249
if ! cat "$CSV_EXPORT" | grep 'n2-standard-8,' | grep 'europe-west4,' | head -n 1 | grep ',249' > /dev/null; then
echo "ERROR: n2-standard-8 in europe-west4 with cost 249 not found"
exit 9
fi
echo "DONE"
================================================
FILE: build/README.md
================================================
# Build
Ready to tweak and test this webapp locally?
Follow these instructions:
## Requirements
* [Google Cloud CLI](https://cloud.google.com/sdk/docs/install) (`gcloud`)
* SQLite3 (`sqlite3`)
* Perl 5 (`perl`)
* Perl modules:
* [App::Options](https://metacpan.org/pod/App::Options)
* [Encode](https://metacpan.org/pod/Encode)
* [YAML::XS](https://metacpan.org/pod/YAML::XS) (and `libyaml`)
* [JSON::XS](https://metacpan.org/pod/JSON::XS)
* [DBD::CSV](https://metacpan.org/pod/DBD::CSV)
* [DBD::SQLite](https://metacpan.org/pod/DBD::SQLite)
* [Template::Toolkit](https://metacpan.org/pod/Template::Toolkit)
* [plackup](https://metacpan.org/dist/Plack/view/script/plackup)
<details>
<summary><b>Debian/Ubuntu</b></summary>
Packages:
```shell
sudo apt update
sudo apt install \
libapp-options-perl \
libdbd-csv-perl \
libdbd-sqlite3-perl \
libencode-perl \
libjson-xs-perl \
libplack-perl \
libtemplate-perl \
libyaml-libyaml-perl \
sqlite3
```
[Google Cloud CLI](https://cloud.google.com/sdk/docs/install#deb):
```shell
sudo apt-get install apt-transport-https ca-certificates gnupg
# Add the gcloud CLI distribution URI as a package source
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
# Import the Google Cloud public key.
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo tee /usr/share/keyrings/cloud.google.gpg
# Update and install the gcloud CLI
sudo apt-get update
sudo apt-get install google-cloud-cli
```
</details>
<details>
<summary><b>macOS</b></summary>
Homebrew packages:
```shell
brew install perl
brew install cpanminus pkg-config
brew install sqlite3
brew install --cask google-cloud-sdk
```
Perl modules:
```shell
cpanm --installdeps .
```
</details>
## Database
Run:
```shell
bash build.sh
```
1. Create SQLite3 database `gce.db` for GCE machine type informations
1. Export all Google Compute Engine machine types ans zones via the Google Compute Engine API to CSV file `machinetypes.csv` and `zones.csv`
1. Copy machine types ans zones from CSV file to SQLite database `gce.db` table `machinetypes` and `zones`
1. Clean up (Remove disconnected data centers...)
1. Copy machine types per region to database table `instances` and disk types per region to table `disks`
1. Add costs for machine types in region from [pricing](https://github.com/Cyclenerd/google-cloud-pricing-cost-calculator)
7. Add [additional machine type informations](../instances/series/)
1. Add CPU platforms and IP addresses
1. Add available CPU platforms per instance in region
1. Add number of public IP addresses for each GCP region
1. Add even more
* Frequency (GHz)
* EEMBC CoreMark Benchmark
* SAP and HANA certified machine types
1. Export CSV and SQL file
1. Test
## Websites
Create:
```shell
perl site.pl
```
No regions and comparison:
```shell
perl site.pl \
--comparison=0 \
--region=0
```
Only `g1-small` and `europe-west4`:
```shell
perl site.pl \
--comparison=1 \
--limit_comparison=g1-small \
--region=1 \
--limit_region=europe-west4
```
This Perl script creates static websites (Templates are located in the [src](./src/) folder).
The websites are stored in the directory `../site/`.
The JavaScript grid library [AG Grid Community](https://www.ag-grid.com/) is used.
Run:
```bash
plackup --host "127.0.0.1" --port "8080"
```
================================================
FILE: build/app.psgi
================================================
#!/usr/bin/env perl
use strict;
use warnings;
use Plack::App::Directory;
my $app = Plack::App::Directory->new({
root => "../site/"
})->to_app;
================================================
FILE: build/build.sh
================================================
#!/usr/bin/env bash
set -e
echo "1. Create"
bash "01_create_database.sh"
echo "2. Get"
bash "02_get.sh"
echo "3. Copy"
perl "03_copy.pl"
echo "4. Clean up"
bash "04_clean_up.sh"
echo "5. Copy instances and disks"
perl "05_copy_instances.pl"
perl "05_copy_disks.pl"
echo "6. Add costs"
perl "06_add_costs.pl"
echo "7. Add informations"
bash "07_add.sh"
echo "8.1. Add available CPU platforms"
perl "08_cpu.pl"
echo "8.2. Add number of public IP addresses"
bash "08_publicipranges.sh"
echo "9. Add more"
bash "09_more.sh"
echo "10. Export"
bash "10_export.sh"
echo "11. Test"
bash "11_test.sh"
================================================
FILE: build/cpanfile
================================================
# Check version with 'cpan -D DBD::SQLite'
recommends 'perl', '5.34';
requires 'App::Options', '1.12';
requires 'Encode', '3.16';
requires 'JSON::XS', '4.03';
requires 'YAML::XS', '0.83';
requires 'DBD::CSV', '0.58';
requires 'DBD::SQLite', '1.70';
requires 'Template::Toolkit', '3.1';
requires 'Plack', '1.0048';
================================================
FILE: build/site.pl
================================================
#!/usr/bin/env perl
# Copyright 2022-2026 Nils Knieling. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Create static website with all GCE machines in regions
#
use utf8;
binmode(STDOUT, ':encoding(utf8)');
use strict;
use DBI;
use Encode qw(decode);
use JSON::XS;
use Template;
use File::Copy;
use App::Options (
option => {
region => {
required => '1',
default => '1',
description => "Create instance in region websites (/:REGION/:INSTANCE.html)"
},
limit_region => {
required => '0',
default => '',
description => "Create websites only for this region"
},
comparison => {
required => '1',
default => '1',
description => "Create instance comparison websites (/comparison/:INSTANCE/vs/:INSTANCE.html)"
},
limit_comparison => {
required => '0',
default => '',
description => "Create comparison websites only for this machine type"
},
site_folder => {
required => '0',
default => '../site/',
description => "Site storage folder path"
},
},
);
my $create_region = $App::options{region};
my $limit_region = $App::options{limit_region};
my $create_comparison = $App::options{comparison};
my $limit_comparison = $App::options{limit_comparison};
my $site_folder = $App::options{site_folder};
# Ensure site_folder ends with a slash
$site_folder .= '/' unless $site_folder =~ /\/$/;
my $db_file = 'gce.db';
my $gmtime = gmtime();
my $timestamp = time();
# Exports
my $csv_export = 'machine-types-regions.csv';
my $sql_export = 'machine-types-regions.sql.gz';
my $filesize_csv_export = -s "$csv_export" || die "ERROR: Cannot get CSV '$csv_export' filesize!\n";
my $filesize_sql_export = -s "$sql_export" || die "ERROR: Cannot get SQL '$sql_export' filesize!\n";
# MiB
$filesize_csv_export = sprintf '%.2f', $filesize_csv_export / 1048576;
$filesize_sql_export = sprintf '%.2f', $filesize_sql_export / 1048576;
print "Create websites...\n";
my $dbh = DBI->connect("dbi:SQLite:dbname=$db_file","","") or die "ERROR: Cannot connect $DBI::errstr\n";
my $template = Template->new(
INCLUDE_PATH => './src',
PRE_PROCESS => 'config.tt2',
VARIABLES => {
'gmtime' => $gmtime,
'timestamp' => $timestamp,
}
);
my @files = ();
###############################################################################
# INSTANCES
###############################################################################
my $sql_instances = qq ~
SELECT
UPPER(series) AS series, name, description, family,
vCpus, LOWER(sharedCpu) AS sharedCpu,
MAX(intel) AS intel,
MAX(amd) AS amd,
MAX(arm) AS arm,
MAX(cpuPlatformCount) AS cpuPlatformCount,
(SELECT cpuPlatform FROM instances WHERE name = I.name ORDER BY cpuPlatformCount) AS cpuPlatform,
MAX(cpuBaseClock) AS cpuBaseClock, MAX(cpuTurboClock) AS cpuTurboClock, MAX(cpuSingleMaxTurboClock) AS cpuSingleMaxTurboClock,
MAX(coremarkScore) AS coremarkScore, MAX(standardDeviation) AS standardDeviation, MAX(sampleCount) AS sampleCount,
memoryGB,
bandwidth, tier1,
disks, disksSizeGb/1024 AS diskSizeTiB, localSsd,
acceleratorCount, acceleratorType,
MAX(sap) AS sap, MAX(saps) AS saps, MAX(hana) AS hana,
MAX(spot) AS spot,
COUNT(region) AS regionCount,
(SELECT GROUP_CONCAT(region) FROM instances WHERE name = I.name ORDER BY region) AS regions,
MAX(sud) AS sud,
ROUND(MIN(hour), 4) AS minHour, ROUND(AVG(hour), 4) AS avgHour, ROUND(MAX(hour), 4) AS maxHour,
ROUND(MIN(hourSpot), 4) AS minHourSpot, ROUND(AVG(hourSpot), 4) AS avgHourSpot, ROUND(MAX(hourSpot), 4) AS maxHourSpot,
ROUND(MIN(month), 2) AS minMonth, ROUND(AVG(month), 2) AS avgMonth, ROUND(MAX(month), 2) AS maxMonth,
ROUND(MIN(month1yCud), 2) AS minMonth1yCud, ROUND(AVG(month1yCud), 2) AS avgMonth1yCud, ROUND(MAX(month1yCud), 2) AS maxMonth1yCud,
ROUND(MIN(month3yCud), 2) AS minMonth3yCud, ROUND(AVG(month3yCud), 2) AS avgMonth3yCud, ROUND(MAX(month3yCud), 2) AS maxMonth3yCud,
ROUND(MIN(monthSpot), 2) AS minMonthSpot, ROUND(AVG(monthSpot), 2) AS avgMonthSpot, ROUND(MAX(monthSpot), 2) AS maxMonthSpot,
ROUND(monthSles, 2) AS monthSles,
ROUND(monthSlesSap, 2) AS monthSlesSap,
ROUND(monthSlesSap1yCud, 2) AS monthSlesSap1yCud,
ROUND(monthSlesSap3yCud, 2) AS monthSlesSap3yCud,
ROUND(monthRhel, 2) AS monthRhel,
ROUND(monthRhel1yCud, 2) AS monthRhel1yCud,
ROUND(monthRhel3yCud, 2) AS monthRhel3yCud,
ROUND(monthRhelSap, 2) AS monthRhelSap,
ROUND(monthRhelSap1yCud, 2) AS monthRhelSap1yCud,
ROUND(monthRhelSap3yCud, 2) AS monthRhelSap3yCud,
ROUND(monthWindows, 2) AS monthWindows
FROM instances I
GROUP BY name
ORDER BY vCpus, name;
~;
my $sth = $dbh->prepare($sql_instances);
$sth->execute();
my @instances = ();
my $id = '1';
while (my $instance = $sth->fetchrow_hashref) {
$instance->{'id'} = $id;
push(@instances, $instance);
$id++;
}
$sth->finish;
push(@files, 'instances.html');
$template->process('instances.tt2', { 'instances' => \@instances }, "${site_folder}instances.html") || die "Template process failed: ", $template->error(), "\n";
# CPU
push(@files, 'intel.html');
$template->process('intel.tt2', { 'instances' => \@instances }, "${site_folder}intel.html") || die "Template process failed: ", $template->error(), "\n";
push(@files, 'amd.html');
$template->process('amd.tt2', { 'instances' => \@instances }, "${site_folder}amd.html") || die "Template process failed: ", $template->error(), "\n";
push(@files, 'arm.html');
$template->process('arm.tt2', { 'instances' => \@instances }, "${site_folder}arm.html") || die "Template process failed: ", $template->error(), "\n";
push(@files, 'gpu.html');
$template->process('gpu.tt2', { 'instances' => \@instances }, "${site_folder}gpu.html") || die "Template process failed: ", $template->error(), "\n";
# SAP
push(@files, 'sap.html');
$template->process('sap.tt2', { 'instances' => \@instances }, "${site_folder}sap.html") || die "Template process failed: ", $template->error(), "\n";
push(@files, 'hana.html');
$template->process('hana.tt2', { 'instances' => \@instances }, "${site_folder}hana.html") || die "Template process failed: ", $template->error(), "\n";
###############################################################################
# DISKS
###############################################################################
my $sql_disks = qq ~
SELECT
name,
description,
COUNT(region) AS regionCount,
ROUND(MIN(monthGb), 2) AS minMonth,
ROUND(AVG(monthGb), 2) AS avgMonth,
ROUND(MAX(monthGb), 2) AS maxMonth
FROM disks D
GROUP BY name
ORDER BY name;
~;
$sth = $dbh->prepare($sql_disks);
$sth->execute();
my @disks = ();
$id = '1';
while (my $disk = $sth->fetchrow_hashref) {
$disk->{'id'} = $id;
push(@disks, $disk);
$id++;
}
$sth->finish;
push(@files, 'disks.html');
$template->process('disks.tt2', { 'disks' => \@disks }, "${site_folder}disks.html") || die "Template process failed: ", $template->error(), "\n";
$template->process('disks.js', {}, "${site_folder}disks.js") || die "Template process failed: ", $template->error(), "\n";
###############################################################################
# DISKS in REGIONS
###############################################################################
my $sql_disks_regions = qq ~
SELECT
region AS name,
regionLocation AS regionLocation,
MAX(zoneCount) AS zoneCount,
(SELECT ROUND(MAX(monthGb), 3) FROM disks WHERE region = D.region AND name = "local-ssd") AS local,
(SELECT ROUND(MAX(monthGb), 3) FROM disks WHERE region = D.region AND name = "pd-balanced") AS balanced,
(SELECT ROUND(MAX(monthGb), 3) FROM disks WHERE region = D.region AND name = "pd-extreme") AS extreme,
(SELECT ROUND(MAX(monthGb), 3) FROM disks WHERE region = D.region AND name = "pd-ssd") AS ssd,
(SELECT ROUND(MAX(monthGb), 3) FROM disks WHERE region = D.region AND name = "pd-standard") AS standard
FROM disks D
GROUP BY region
ORDER BY region;
~;
$sth = $dbh->prepare($sql_disks_regions);
$sth->execute();
my @disks_regions = ();
while (my $region = $sth->fetchrow_hashref) {
push(@disks_regions, $region);
}
$sth->finish;
# Regions
push(@files, 'diskpricing.html');
$template->process('diskpricing.tt2', { 'disks_regions' => \@disks_regions }, "${site_folder}diskpricing.html") || die "Template process failed: ", $template->error(), "\n";
###############################################################################
# REGIONS
###############################################################################
my $sql_regions = qq ~
SELECT
region AS name,
regionLocation AS regionLocation,
regionLocationLong AS regionLocationLong,
regionLocationCountryCode AS regionLocationCountryCode,
regionCfe AS regionCfe,
regionCo2Kwh AS regionCo2Kwh,
regionLowCo2 AS regionLowCo2,
regionLat AS regionLat,
regionLng AS regionLng,
MAX(regionPublicIpv4Addr) AS regionPublicIpv4Addr,
MAX(zoneCount) AS zoneCount,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Haswell%") AS intelHaswell,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Broadwell%") AS intelBroadwell,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Skylake%") AS intelSkylake,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Cascade Lake%") AS intelCascadeLake,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Ice Lake%") AS intelIceLake,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Sapphire%") AS intelSapphireRapids,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Emerald%") AS intelEmeraldRapids,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Granite%") AS intelGraniteRapids,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Rome%") AS amdRome,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Milan%") AS amdMilan,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Genoa%") AS amdGenoa,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Turin%") AS amdTurin,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Altra%") AS armAmpereAltra,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND availableCpuPlatform LIKE "%Axion%") AS armGoogleAxion,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND family LIKE "%General%") AS generalCount,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND family LIKE "%Compute%") AS computeCount,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND family LIKE "%Memory%") AS memoryCount,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND family LIKE "%Accelerator%") AS acceleratorCount,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND family LIKE "%Storage%") AS storageCount,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND sap >= 1) AS sap,
(SELECT COUNT(name) FROM instances WHERE region = I.region AND hana >= 1) AS hana,
(SELECT ROUND(MIN(hour), 4) FROM instances WHERE region = I.region AND name LIKE "e2-standard-8") AS e2Standard8Hour,
(SELECT ROUND(MIN(month), 2) FROM instances WHERE region = I.region AND name LIKE "e2-standard-8") AS e2Standard8Month
FROM instances I
GROUP BY region
ORDER BY region;
~;
$sth = $dbh->prepare($sql_regions);
$sth->execute();
my @regions = ();
$id = '1';
while (my $region = $sth->fetchrow_hashref) {
$region->{'id'} = $id;
push(@regions, $region);
$id++;
}
$sth->finish;
# Regions
push(@files, 'regions.html');
$template->process('regions.tt2', { 'regions' => \@regions }, "${site_folder}regions.html") || die "Template process failed: ", $template->error(), "\n";
# Map with regions
push(@files, 'map.html');
$template->process('map.tt2', { 'regions' => \@regions }, "${site_folder}map.html") || die "Template process failed: ", $template->error(), "\n";
# CPU platforms in regions
push(@files, 'platforms.html');
$template->process('platforms.tt2', { 'regions' => \@regions }, "${site_folder}platforms.html") || die "Template process failed: ", $template->error(), "\n";
###############################################################################
# REGION
###############################################################################
# Instances in Region
foreach my $region (@regions) {
my $name = $region->{'name'} || 'missing';
# Instances
my $sql_instances_in_region = qq ~
SELECT
UPPER(series) AS series, name, description, family,
vCpus, LOWER(sharedCpu) AS sharedCpu,
intel, amd, arm, availableCpuPlatformCount, cpuPlatformCount,
cpuBaseClock, cpuTurboClock, cpuSingleMaxTurboClock,
memoryGB,
sap, saps, hana,
zoneCount,
sud,
ROUND(hour, 4) AS hour,
ROUND(hourSpot, 4) AS hourSpot,
ROUND(month, 2) AS month,
ROUND(month1yCud, 2) AS month1yCud,
ROUND(month3yCud, 2) AS month3yCud,
ROUND(monthSpot, 2) AS monthSpot,
ROUND(monthSles, 2) AS monthSles,
ROUND(monthSlesSap, 2) AS monthSlesSap,
ROUND(monthSlesSap1yCud, 2) AS monthSlesSap1yCud,
ROUND(monthSlesSap3yCud, 2) AS monthSlesSap3yCud,
ROUND(monthRhel, 2) AS monthRhel,
ROUND(monthRhel1yCud, 2) AS monthRhel1yCud,
ROUND(monthRhel3yCud, 2) AS monthRhel3yCud,
ROUND(monthRhelSap, 2) AS monthRhelSap,
ROUND(monthRhelSap1yCud, 2) AS monthRhelSap1yCud,
ROUND(monthRhelSap3yCud, 2) AS monthRhelSap3yCud,
ROUND(monthWindows, 2) AS monthWindows
FROM instances
WHERE region LIKE '$name'
ORDER BY vCpus, name;
~;
$sth = $dbh->prepare($sql_instances_in_region);
$sth->execute();
my @instances_in_region = ();
$id = '1';
while (my $instance = $sth->fetchrow_hashref) {
$instance->{'id'} = $id;
push(@instances_in_region, $instance);
$id++;
}
# Disks
my $sql_disks_in_region = qq ~
SELECT
name,
description,
zoneCount,
monthGb
FROM disks
WHERE region LIKE '$name'
ORDER BY name;
~;
$sth = $dbh->prepare($sql_disks_in_region);
$sth->execute();
my @disks_in_region = ();
$id = '1';
while (my $disk = $sth->fetchrow_hashref) {
$disk->{'id'} = $id;
push(@disks_in_region, $disk);
$id++;
}
my $html_file = "${site_folder}$name.html";
print "$html_file\n";
push(@files, "$name".'.html');
$template->process('region.tt2', {
'region' => $region,
'regions' => \@regions,
'instances' => \@instances,
'disks_in_region' => \@disks_in_region,
'instances_in_region' => \@instances_in_region
}, "$html_file") || die "Template process failed: ", $template->error(), "\n";
}
###############################################################################
# INSTANCE
###############################################################################
# Instance in Regions
foreach my $instance (@instances) {
my $name = $instance->{'name'} || 'missing';
my $sql_instance_regions = qq ~
SELECT
region AS name,
regionLocation AS regionLocation,
regionCfe AS regionCfe,
regionCo2Kwh AS regionCo2Kwh,
regionLowCo2 AS regionLowCo2,
zoneCount AS zoneCount,
availableCpuPlatformCount AS availableCpuPlatformCount,
ROUND(hour, 4) AS hour,
ROUND(hourSpot, 4) AS hourSpot,
ROUND(month, 2) AS month,
ROUND(month1yCud, 2) AS month1yCud,
ROUND(month3yCud, 2) AS month3yCud,
ROUND(monthSpot, 2) AS monthSpot,
ROUND(monthSles, 2) AS monthSles,
ROUND(monthSlesSap, 2) AS monthSlesSap,
ROUND(monthSlesSap1yCud, 2) AS monthSlesSap1yCud,
ROUND(monthSlesSap3yCud, 2) AS monthSlesSap3yCud,
ROUND(monthRhel, 2) AS monthRhel,
ROUND(monthRhel1yCud, 2) AS monthRhel1yCud,
ROUND(monthRhel3yCud, 2) AS monthRhel3yCud,
ROUND(monthRhelSap, 2) AS monthRhelSap,
ROUND(monthRhelSap1yCud, 2) AS monthRhelSap1yCud,
ROUND(monthRhelSap3yCud, 2) AS monthRhelSap3yCud,
ROUND(monthWindows, 2) AS monthWindows
FROM instances
WHERE name LIKE '$name'
ORDER BY hour, region;
~;
$sth = $dbh->prepare($sql_instance_regions);
$sth->execute();
my @instance_regions = ();
$id = '1';
while (my $region = $sth->fetchrow_hashref) {
$region->{'id'} = $id;
push(@instance_regions, $region);
$id++;
}
$sth->finish;
my $html_file = "${site_folder}$name.html";
print "$html_file\n";
push(@files, "$name".'.html');
$template->process('instance.tt2', {
'instance' => $instance,
'instances' => \@instances,
'regions' => \@instance_regions
}, "$html_file") || die "Template process failed: ", $template->error(), "\n";
}
###############################################################################
# DISK
###############################################################################
# Disk in Regions
foreach my $disk (@disks) {
my $name = $disk->{'name'} || 'missing';
my $sql_disk_regions = qq ~
SELECT
region AS name,
regionLocation AS regionLocation,
zoneCount AS zoneCount,
monthGb
FROM disks
WHERE name LIKE '$name'
ORDER BY monthGb, region;
~;
$sth = $dbh->prepare($sql_disk_regions);
$sth->execute();
my @disk_regions = ();
$id = '1';
while (my $region = $sth->fetchrow_hashref) {
$region->{'id'} = $id;
push(@disk_regions, $region);
$id++;
}
$sth->finish;
my $html_file = "${site_folder}$name.html";
print "$html_file\n";
push(@files, "$name".'.html');
$template->process('disk.tt2', {
'disk' => $disk,
'regions' => \@disk_regions
}, "$html_file") || die "Template process failed: ", $template->error(), "\n";
}
###############################################################################
# INSTANCE in REGION
###############################################################################
# Zones
my $sql_zones = "SELECT name, availableCpuPlatforms FROM zones ORDER BY name";
$sth = $dbh->prepare($sql_zones);
$sth->execute();
my @zones = ();
$id = '1';
while (my $zone = $sth->fetchrow_hashref) {
$zone->{'id'} = $id;
push(@zones, $zone);
$id++;
}
$sth->finish;
# Instance in Region
my $sql_instance_in_region = qq ~
SELECT
UPPER(series) AS series, name, description, family,
vCpus, LOWER(sharedCpu) AS sharedCpu,
cpuPlatform, cpuPlatformCount,
intel, amd, arm, availableCpuPlatform, availableCpuPlatformCount,
(cpuPlatformCount - availableCpuPlatformCount) AS notAvailableCpuPlatformCount,
cpuBaseClock, cpuTurboClock, cpuSingleMaxTurboClock,
ROUND(coremarkScore, 0) AS coremarkScore,
ROUND(standardDeviation, 0) AS standardDeviation,
ROUND(sampleCount, 0) AS sampleCount,
memoryGB,
bandwidth, tier1,
disks, disksSizeGb/1024 AS diskSizeTiB, localSsd,
ROUND(acceleratorCount, 0) AS acceleratorCount,
acceleratorType,
sap, saps, hana,
spot,
region, regionLocation, regionLocationLong, regionLocationCountryCode, regionCfe, regionCo2Kwh, regionLowCo2, regionLat, regionLng,
zoneCount, zones,
sud,
ROUND(hour, 4) AS hour,
ROUND(hourSpot, 4) AS hourSpot,
ROUND(month, 2) AS month,
ROUND(month1yCud, 2) AS month1yCud,
ROUND(month3yCud, 2) AS month3yCud,
ROUND(monthSpot, 2) AS monthSpot,
ROUND(monthSles, 2) AS monthSles,
ROUND(monthSlesSap, 2) AS monthSlesSap,
ROUND(monthSlesSap1yCud, 2) AS monthSlesSap1yCud,
ROUND(monthSlesSap3yCud, 2) AS monthSlesSap3yCud,
ROUND(monthRhel, 2) AS monthRhel,
ROUND(monthRhel1yCud, 2) AS monthRhel1yCud,
ROUND(monthRhel3yCud, 2) AS monthRhel3yCud,
ROUND(monthRhelSap, 2) AS monthRhelSap,
ROUND(monthRhelSap1yCud, 2) AS monthRhelSap1yCud,
ROUND(monthRhelSap3yCud, 2) AS monthRhelSap3yCud,
ROUND(monthWindows, 2) AS monthWindows,
ROUND(coremarkScore/hour, 0) AS coremarkHour,
ROUND(coremarkScore/hourSpot, 0) AS coremarkHourSpot,
ROUND(saps/hour, 0) AS sapsHour
FROM instances
ORDER BY name, region;
~;
my $sth = $dbh->prepare($sql_instance_in_region);
$sth->execute();
my @instances_in_regions = ();
my $id = '1';
while (my $instance = $sth->fetchrow_hashref) {
my $name = $instance->{'name'} || 'missing';
my $region = $instance->{'region'} || 'missing';
next if ($limit_region && $limit_region ne "$region"); # skip region if limit is set
$instance->{'id'} = $id;
push(@instances_in_regions, $instance);
if ($create_region) {
my $html_file = "${site_folder}$region/$name.html";
print "$id : $html_file\n";
$template->process('instance_in_region.tt2', {
'instance' => $instance,
'regions' => \@regions,
'zones' => \@zones,
}, "$html_file") || die "Template process failed: ", $template->error(), "\n";
}
$id++;
}
$sth->finish;
###############################################################################
# COMPARISON
###############################################################################
if ($create_comparison) {
my $id = '1';
foreach my $instance_a (@instances) {
my $name_a = $instance_a->{'name'} || 'missing';
next if ($limit_comparison && $name_a ne "$limit_comparison");
$template->process('vs.tt2', {
'instance_a' => $instance_a,
'instances' => \@instances
}, "${site_folder}comparison/$name_a/vs.html") || die "Template process failed: ", $template->error(), "\n";
foreach my $instance_b (@instances) {
my $name_b = $instance_b->{'name'} || 'missing';
next if ($name_a eq $name_b);
# Costs in regions for instance A
my $sql_regions_for_a = qq ~
SELECT
region AS region,
regionLocation AS regionLocation,
regionCfe AS regionCfe,
regionCo2Kwh AS regionCo2Kwh,
regionLowCo2 AS regionLowCo2,
zoneCount AS zoneCount,
availableCpuPlatformCount AS availableCpuPlatformCount,
ROUND(hour, 4) AS hour,
ROUND(hourSpot, 4) AS hourSpot,
ROUND(month, 2) AS month,
ROUND(month1yCud, 2) AS month1yCud,
ROUND(month3yCud, 2) AS month3yCud,
ROUND(monthSpot, 2) AS monthSpot
FROM instances
WHERE name LIKE '$name_a'
ORDER BY region;
~;
$sth = $dbh->prepare($sql_regions_for_a);
$sth->execute();
my @regions_a = ();
while (my $region = $sth->fetchrow_hashref) {
push(@regions_a, $region);
}
$sth->finish;
# Costs in regions for instance B
my $sql_regions_for_b = qq ~
SELECT
region AS region,
regionLocation AS regionLocation,
regionCfe AS regionCfe,
regionCo2Kwh AS regionCo2Kwh,
regionLowCo2 AS regionLowCo2,
zoneCount AS zoneCount,
availableCpuPlatformCount AS availableCpuPlatformCount,
ROUND(hour, 4) AS hour,
ROUND(hourSpot, 4) AS hourSpot,
ROUND(month, 2) AS month,
ROUND(month1yCud, 2) AS month1yCud,
ROUND(month3yCud, 2) AS month3yCud,
ROUND(monthSpot, 2) AS monthSpot
FROM instances
WHERE name LIKE '$name_b'
ORDER BY region;
~;
$sth = $dbh->prepare($sql_regions_for_b);
$sth->execute();
my @regions_b = ();
while (my $region = $sth->fetchrow_hashref) {
push(@regions_b, $region);
}
$sth->finish;
my $html_file = "${site_folder}comparison/$name_a/vs/$name_b.html";
print "$id : $html_file\n";
$template->process('comparison.tt2', {
'instances' => \@instances,
'instance_a' => $instance_a,
'instance_b' => $instance_b,
'regions' => \@regions,
'regions_a' => \@regions_a,
'regions_b' => \@regions_b,
}, "$html_file") || die "Template process failed: ", $template->error(), "\n";
$id++;
}
}
}
###############################################################################
# IMAGES
###############################################################################
# Operating system details: https://cloud.google.com/compute/docs/images/os-details
$sth = $dbh->prepare("SELECT project AS name, COUNT(name) as imageCount FROM images GROUP BY project ORDER BY project ASC");
$sth->execute();
my @image_projects = ();
while (my $image_project = $sth->fetchrow_hashref) {
push(@image_projects, $image_project);
}
$sth->finish;
my $sql_image_family = qq ~
SELECT
project,
family AS name,
(SELECT name FROM images WHERE project LIKE I.project AND family LIKE I.family ORDER BY creation DESC LIMIT 1) AS image,
(SELECT architecture FROM images WHERE project LIKE I.project AND family LIKE I.family ORDER BY creation DESC LIMIT 1) AS architecture,
(SELECT description FROM images WHERE project LIKE I.project AND family LIKE I.family ORDER BY creation DESC LIMIT 1) AS description,
(SELECT MAX(diskSizeGb) FROM images WHERE project LIKE I.project AND family LIKE I.family ORDER BY creation DESC LIMIT 1) AS diskSizeGb,
(SELECT creation FROM images WHERE project LIKE I.project AND family LIKE I.family ORDER BY creation DESC LIMIT 1) AS creation
FROM images I
GROUP BY project, family
ORDER BY family DESC;
~;
$sth = $dbh->prepare($sql_image_family);
$sth->execute();
my @image_families = ();
while (my $image_family = $sth->fetchrow_hashref) {
push(@image_families, $image_family);
}
$sth->finish;
push(@files, 'images.html');
$template->process('images.tt2', {
'image_projects' => \@image_projects,
'image_famlies' => \@image_families
}, "${site_folder}images.html") || die "Template process failed: ", $template->error(), "\n";
###############################################################################
# MISC
###############################################################################
# Index
$template->process('index.tt2', {
'instances' => \@instances,
'disks' => \@disks,
'regions' => \@regions,
'instances_in_regions' => \@instances_in_regions
}, "${site_folder}index.html") || die "Template process failed: ", $template->error(), "\n";
# Grid
push(@files, 'grid.html');
my $json = encode_json \@instances_in_regions;
$json = decode('UTF-8', $json); # force UTF-8
$template->process('main.js', {}, "${site_folder}main.js") || die "Template process failed: ", $template->error(), "\n";
$template->process('grid.tt2', {}, "${site_folder}grid.html") || die "Template process failed: ", $template->error(), "\n";
$template->process('instance_in_region.json', { 'json' => $json }, "${site_folder}instance_in_region.json") || die "Template process failed: ", $template->error(), "\n";
# Download
push(@files, 'download.html');
$template->process('download.tt2', {
'csvFileSize' => $filesize_csv_export,
'sqlFileSize' => $filesize_sql_export,
}, "${site_folder}download.html") || die "Template process failed: ", $template->error(), "\n";
# gcosts
push(@files, 'gcosts.html');
$template->process('gcosts.tt2', {}, "${site_folder}gcosts.html") || die "Template process failed: ", $template->error(), "\n";
# Imprint
$template->process('imprint.tt2', {}, "${site_folder}imprint.html") || die "Template process failed: ", $template->error(), "\n";
# 404
$template->process('404.tt2', {}, "${site_folder}404.html") || die "Template process failed: ", $template->error(), "\n";
# Sitemap
$template->process('sitemap.tt2', { 'files' => \@files }, "${site_folder}sitemap.txt") || die "Template process failed: ", $template->error(), "\n";
# Robots.txt
$template->process('robots.txt', {
'regions' => \@regions
}, "${site_folder}robots.txt") || die "Template process failed: ", $template->error(), "\n";
# SQL and CSV Export
copy("$sql_export", "${site_folder}machine-types-regions.sql.gz");
copy("$csv_export", "${site_folder}machine-types-regions.csv");
# Images
mkdir("${site_folder}img/");
my @images = (
'combine-filter.png',
'csv.png',
'filter.png',
'gcosts.png',
'show-more.png',
'social.png',
'sort.png',
'usage.png',
);
foreach my $image (@images) {
copy("./src/img/$image", "${site_folder}img/$image");
}
# Favicon
my @favicons = (
'favicon.ico',
'favicon-16x16.png',
'favicon-32x32.png',
'apple-touch-icon.png',
'android-chrome-192x192.png',
'android-chrome-512x512.png',
'site.webmanifest',
);
foreach my $favicon (@favicons) {
copy("./src/img/favicon/$favicon", "${site_folder}$favicon");
}
copy("./src/ads.txt", "${site_folder}ads.txt");
copy("./src/popin-min.js", "${site_folder}popin-min.js");
print "DONE\n";
================================================
FILE: build/src/404.tt2
================================================
[%- PROCESS header.tt2 -%]
</div> <!-- // container-fluid -->
<div class="container">
<h1>404 - Page Not Found</h1>
<blockquote class="blockquote">
<p>Sorry, the <a href="/instances.html">machine type</a>, <a href="/regions.html">region</a> or page you are looking for could not be found.</p>
</blockquote>
<p>
<a class="btn btn-primary btn-lg" href="/" role="button">Start</a>
</p>
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/ads.txt
================================================
google.com, pub-7267449040388963, DIRECT, f08c47fec0942fa0
================================================
FILE: build/src/amd.tt2
================================================
[%- PROCESS header.tt2 -%]
[%- PROCESS instances_header.tt2 -%]
<h1>Google Compute Engine Machine Types with AMD CPU Platform</h1>
[%- countAmd = 0; FOREACH instance IN instances; IF instance.amd; countAmd = countAmd + 1; END; END -%]
<blockquote class="blockquote">
<p>
There are <mark>[% countAmd %]</mark> Google Compute Engine machine types with AMD central processing unit (CPU) available.
Not every Google Cloud VM with AMD CPU is available in every region.
</p>
</blockquote>
<p><a class="btn btn-success" href="/grid.html?platform=amd" role="button">✅ Instance Picker with filter on CPU Platform</a></p>
<div class="table-responsive">
[%- PROCESS instances_tr.tt2; -%]
<table
class="table table-sm table-hover table-bordered"
data-classes="table table-sm table-hover table-bordered"
data-toggle="table"
data-sort-name="vcpu"
data-sort-order="asc"
data-sortable="true"
data-sticky-header="true"
>
<thead>
[%- instancePlatformTh() -%]
</thead>
<tbody>
[%- FOREACH instance IN instances; IF instance.amd; instancePlatformTr(instance); END; END -%]
</tbody>
</table>
</div> <!-- // table-responsive -->
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/arm.tt2
================================================
[%- PROCESS header.tt2 -%]
[%- PROCESS instances_header.tt2 -%]
<h1>Google Compute Engine Machine Types with Arm CPU Platform</h1>
[%- countArm = 0; FOREACH instance IN instances; IF instance.arm; countArm = countArm + 1; END; END -%]
<blockquote class="blockquote">
<p>
There are <mark>[% countArm %]</mark> Google Compute Engine machine types with Arm-based central processing unit (CPU) available.
Not every Google Cloud VM with Arm-based CPU is available in every region.
</p>
</blockquote>
<p><a class="btn btn-success" href="/grid.html?arm=1" role="button">✅ Instance Picker with filter on Arm-based CPU</a></p>
<div class="table-responsive">
[%- PROCESS instances_tr.tt2; -%]
<table
class="table table-sm table-hover table-bordered"
data-classes="table table-sm table-hover table-bordered"
data-toggle="table"
data-sort-name="vcpu"
data-sort-order="asc"
data-sortable="true"
data-sticky-header="true"
>
<thead>
[%- instancePlatformTh() -%]
</thead>
<tbody>
[%- FOREACH instance IN instances; IF instance.arm; instancePlatformTr(instance); END; END -%]
</tbody>
</table>
</div> <!-- // table-responsive -->
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/comparison.tt2
================================================
[%- PROCESS header.tt2 -%]
<h1>Google Compute Engine Comparison [% instance_a.name %] vs. [% instance_b.name %]</h1>
<blockquote class="blockquote">
<p>
Google Compute Engine machine type comparison
<a href="/[% instance_a.name %].html" title="Show machine type [% instance_a.name %] in all regions">[% instance_a.name %]</a>
([% instance_a.vCpus %] vCPU, [% instance_a.memoryGB %] GB memory)
versus
<a href="/[% instance_b.name %].html" title="Show machine type [% instance_b.name %] in all regions">[% instance_b.name %]</a>
([% instance_b.vCpus %] vCPU, [% instance_b.memoryGB %] GB memory).
</p>
</blockquote>
<p class="d-grid gap-2 d-lg-block">
<a class="btn btn-primary" href="/[% instance_a.name %].html" role="button" title="Show machine type [% instance_a.name %] in all regions">Show [% instance_a.name %]</a>
<a class="btn btn-primary" href="/[% instance_b.name %].html" role="button" title="Show machine type [% instance_b.name %] in all regions">Show [% instance_b.name %]</a>
<a class="btn btn-warning" href="/comparison/[% instance_a.name %]/vs.html" role="button">Compare [% instance_a.name %]</a>
<a class="btn btn-warning" href="/comparison/[% instance_b.name %]/vs.html" role="button">Compare [% instance_b.name %]</a>
</p>
<div class="row">
<div class="col-xxl-6">
<h2>Google Cloud VMs</h2>
<p>Technical facts about the Google Compute Engine machine types [% instance_a.name %] and [% instance_b.name %].</p>
<div class="table-responsive">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" class="table-active">[% instance_a.name %]</th>
<th scope="col"></th>
<th scope="col">[% instance_b.name %]</th>
</tr>
</thead>
<tbody>
<tr>
<th>Series</th>
<td class="table-active">[% instance_a.series %]</td>
[% tableCompareText(instance_a.series || '', instance_b.series || '') %]
<td>[% instance_b.series %]</td>
</tr>
<tr>
<th>Family</th>
<td class="table-active">[% instance_a.family %]</td>
[% tableCompareText(instance_a.family || '', instance_b.family || '') %]
<td>[% instance_b.family %]</td>
</tr>
<tr>
<th>Regions</th>
<td class="table-active">[% instance_a.regionCount %]</td>
[% tableCompareNumber(instance_a.regionCount || 0, instance_b.regionCount || 0) %]
<td>[% instance_b.regionCount %]</td>
</tr>
<tr>
<th>vCPU</th>
<td class="table-active">[% instance_a.vCpus %][% badgeSharedCpu(instance_a) %]</td>
[% tableCompareNumber(instance_a.vCpus || 0, instance_b.vCpus || 0) %]
<td>[% instance_b.vCpus %][% badgeSharedCpu(instance_b) %]</td>
</tr>
<tr>
<th>Memory</th>
<td class="table-active">[% instance_a.memoryGB %] GB</td>
[% tableCompareNumber(instance_a.memoryGB || 0, instance_b.memoryGB || 0) %]
<td>[% instance_b.memoryGB %] GB</td>
</tr>
<tr>
<th>CPU Platform</th>
<td class="table-active">[% listCpuPlatform(instance_a) %]</td>
[% tableCompareNumber(instance_a.cpuPlatformCount || 0, instance_b.cpuPlatformCount || 0) %]
<td>[% listCpuPlatform(instance_b) %]</td>
</tr>
<tr>
<th>CPU Base Frequency</th>
<td class="table-active">[% instance_a.cpuBaseClock %] GHz</td>
[% tableCompareNumber(instance_a.cpuBaseClock || 0, instance_b.cpuBaseClock || 0) %]
<td>[% instance_b.cpuBaseClock %] GHz</td>
</tr>
<tr>
<th>CPU Turbo Frequency</th>
<td class="table-active">[% instance_a.cpuTurboClock %] GHz</td>
[% tableCompareNumber(instance_a.cpuTurboClock || 0, instance_b.cpuTurboClock || 0) %]
<td>[% instance_b.cpuTurboClock %] GHz</td>
</tr>
<tr>
<th>CPU Max. Turbo Frequency</th>
<td class="table-active">[% instance_a.cpuSingleMaxTurboClock %] GHz</td>
[% tableCompareNumber(instance_a.cpuSingleMaxTurboClock || 0, instance_b.cpuSingleMaxTurboClock || 0) %]
<td>[% instance_b.cpuSingleMaxTurboClock %] GHz</td>
</tr>
<tr>
<th>Accelerator (GPUs)</th>
<td class="table-active">[% instance_a.acceleratorCount %]</td>
[% tableCompareNumber(instance_a.acceleratorCount || 0, instance_b.acceleratorCount || 0) %]
<td>[% instance_b.acceleratorCount %]</td>
</tr>
<tr>
<th>Accelerator Type</th>
<td class="table-active">[% instance_a.acceleratorType %]</td>
[% tableCompareText(instance_a.acceleratorType || '', instance_b.acceleratorType || '') %]
<td>[% instance_b.acceleratorType %]</td>
</tr>
<tr>
<th>EEMBC CoreMark Benchmark (<a href="https://www.eembc.org/coremark">?</a>)</th>
<td class="table-active">[% IF instance_a.coremarkScore %][% instance_a.coremarkScore %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
[% tableCompareNumber(instance_a.coremarkScore || 0, instance_b.coremarkScore || 0) %]
<td>[% IF instance_b.coremarkScore %][% instance_b.coremarkScore %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>EEMBC CoreMark Standard Deviation</th>
<td class="table-active">[% IF instance_a.standardDeviation %][% instance_a.standardDeviation %] %[% ELSE %]<span class="text-muted">-</span>[% END %]</td>
[% tableCompareNumber(instance_a.standardDeviation || 0, instance_b.standardDeviation || 0) %]
<td>[% IF instance_b.standardDeviation %][% instance_b.standardDeviation %] %[% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>EEMBC CoreMark Sample Count</th>
<td class="table-active">[% IF instance_a.sampleCount %][% instance_a.sampleCount %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
[% tableCompareNumber(instance_a.sampleCount || 0, instance_b.sampleCount || 0) %]
<td>[% IF instance_b.sampleCount %][% instance_b.sampleCount %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>SAP Standard Benchmark (<a href="https://www.sap.com/about/benchmark.html">?</a>)</th>
<td class="table-active">[% IF instance_a.saps %][% instance_a.saps %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
[% tableCompareNumber(instance_a.saps || 0, instance_b.saps || 0) %]
<td>[% IF instance_b.saps %][% instance_b.saps %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>Network Bandwidth</th>
<td class="table-active">[% instance_a.bandwidth %] Gbps</td>
[% tableCompareNumber(instance_a.bandwidth || 0, instance_b.bandwidth || 0) %]
<td>[% instance_b.bandwidth %] Gbps</td>
</tr>
<tr>
<th>Network Tier 1</th>
<td class="table-active">[% IF instance_a.tier1 %][% instance_a.tier1 %] Gbps[% ELSE %]<span class="text-muted">-</span>[% END %]</td>
[% tableCompareNumber(instance_a.tier1 || 0, instance_b.tier1 || 0) %]
<td>[% IF instance_b.tier1 %][% instance_b.tier1 %] Gbps[% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th title="Disk usage is charged separately from machine type pricing!">Max. Disk Size</th>
<td class="table-active">[% instance_a.diskSizeTiB %] TB</td>
[% tableCompareNumber(instance_a.diskSizeTiB || 0, instance_b.diskSizeTiB || 0) %]
<td>[% instance_b.diskSizeTiB %] TB</td>
</tr>
<tr>
<th title="Disk usage is charged separately from machine type pricing!">Max. Number of Disks</th>
<td class="table-active">[% instance_a.disks %]</td>
[% tableCompareNumber(instance_a.disks || 0, instance_b.disks || 0) %]
<td>[% instance_b.disks %]</td>
</tr>
<tr>
<th>Local SSD</th>
<td class="table-active">[% booleanLocalSsd(instance_a) %]</td>
[% tableCompareBoolean(instance_a.localSsd || 0, instance_b.localSsd || 0) %]
<td>[% booleanLocalSsd(instance_b) %]</td>
</tr>
<tr>
<th>SAP Application</th>
<td class="table-active">[% booleanSap(instance_a) %]</td>
[% tableCompareBoolean(instance_a.sap || 0, instance_b.sap || 0) %]
<td>[% booleanSap(instance_b) %]</td>
</tr>
<tr>
<th>SAP HANA</th>
<td class="table-active">[% booleanHana(instance_a) %]</td>
[% tableCompareBoolean(instance_a.hana || 0, instance_b.hana || 0) %]
<td>[% booleanHana(instance_b) %]</td>
</tr>
<tr>
<th>Spot Provisioning Mode (Spot VM)</th>
<td class="table-active">[% booleanSpot(instance_a) %]</td>
[% tableCompareBoolean(instance_a.spot || 0, instance_b.spot || 0) %]
<td>[% booleanSpot(instance_b) %]</td>
</tr>
<tr>
<th>Sustained Use Discount (SUD)</th>
<td class="table-active">[% booleanSud(instance_a) %]</td>
[% tableCompareBoolean(instance_a.sud || 0, instance_b.sud || 0) %]
<td>[% booleanSud(instance_b) %]</td>
</tr>
</tbody>
<tr>
<th scope="col"></th>
<th scope="col" class="table-active">[% instance_a.name %]</th>
<th scope="col"></th>
<th scope="col">[% instance_b.name %]</th>
</tr>
<tfoot>
</tfoot>
</table>
</div> <!-- // table-responsive -->
</div> <!-- // col -->
<div class="col-xxl-6">
<h2>Costs (Pricing)</h2>
<p>Average prices across all regions for Google Compute Engine machine types [% instance_a.name %] and [% instance_b.name %].</p>
<h3>Price per Hour</h3>
<div class="table-responsive">
<table class="table table-hover table-striped table-bordered">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" class="table-active">[% instance_a.name %]</th>
<th scope="col"></th>
<th scope="col">[% instance_b.name %]</th>
</tr>
</thead>
<tbody>
<tr>
<th>Standard price per hour</th>
<td class="currency table-active">[% instance_a.avgHour %]</td>
[% tableCompareCosts(instance_a.avgHour || 0, instance_b.avgHour || 0) %]
<td class="currency">[% instance_b.avgHour %]</td>
</tr>
<tr>
<th>Spot provisioning model (Spot VM)</th>
<td class="currency table-active">[% instance_a.avgHourSpot %]</td>
[% tableCompareCosts(instance_a.avgHourSpot || 0, instance_b.avgHourSpot || 0) %]
<td class="currency">[% instance_b.avgHourSpot %]</td>
</tr>
</tbody>
</table>
</div>
<h3>Price per Month</h3>
<div class="table-responsive">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" class="table-active">[% instance_a.name %]</th>
<th scope="col"></th>
<th scope="col">[% instance_b.name %]</th>
</tr>
</thead>
<tbody>
<tr>
<th>Price per month</th>
<td class="table-active">
<span class="currency">[% instance_a.avgMonth %]</span>
[% badgeSud(instance_a) %]
</td>
[% tableCompareCosts(instance_a.avgMonth || 0, instance_b.avgMonth || 0) %]
<td>
<span class="currency">[% instance_b.avgMonth %]</span>
[% badgeSud(instance_b) %]
</td>
</tr>
<tr>
<th>Spot provisioning model (Spot VM)</th>
<td class="currency table-active">[% instance_a.avgMonthSpot %]</td>
[% tableCompareCosts(instance_a.avgMonthSpot || 0, instance_b.avgMonthSpot || 0) %]
<td class="currency">[% instance_b.avgMonthSpot %]</td>
</tr>
<tr>
<th>1 year commitment (CUD)</th>
<td class="currency table-active">[% instance_a.avgMonth1yCud %]</td>
[% tableCompareCosts(instance_a.avgMonth1yCud || 0, instance_b.avgMonth1yCud || 0) %]
<td class="currency">[% instance_b.avgMonth1yCud %]</td>
</tr>
<tr>
<th>3 year commitment (CUD)</th>
<td class="currency table-active">[% instance_a.avgMonth3yCud %]</td>
[% tableCompareCosts(instance_a.avgMonth3yCud || 0, instance_b.avgMonth3yCud || 0) %]
<td class="currency">[% instance_b.avgMonth3yCud %]</td>
</tr>
</tbody>
</table>
</div> <!-- // table-responsive -->
<h3>Operating System Licenses Costs</h3>
<p>Monthly costs for paid <i>premium</i> operating system licenses for Google Compute Engine machine types [% instance_a.name %] and [% instance_b.name %].</p>
<div class="table-responsive">
<table class="table table-hover table-bordered">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" class="table-active">[% instance_a.name %]</th>
<th scope="col"></th>
<th scope="col">[% instance_b.name %]</th>
</tr>
</thead>
<tbody>
<tr>
<th>Microsoft Windows Server</th>
<td class="currency table-active">[% instance_a.monthWindows %]</td>
[% tableCompareCosts(instance_a.monthWindows || 0, instance_b.monthWindows || 0) %]
<td class="currency">[% instance_b.monthWindows %]</td>
</tr>
<tr>
<th>SUSE Linux Enterprise Server</th>
<td class="currency table-active">[% instance_a.monthSles %]</td>
[% tableCompareCosts(instance_a.monthSles || 0, instance_b.monthSles || 0) %]
<td class="currency">[% instance_b.monthSles %]</td>
</tr>
<tr>
<th>Red Hat Enterprise Linux</th>
<td class="currency table-active">[% instance_a.monthRhel %]</td>
[% tableCompareCosts(instance_a.monthRhel || 0, instance_b.monthRhel || 0) %]
<td class="currency">[% instance_b.monthRhel %]</td>
</tr>
<tr>
<th>Red Hat Enterprise Linux w. 1 year CUD</th>
<td class="currency table-active">[% instance_a.monthRhel1yCud %]</td>
[% tableCompareCosts(instance_a.monthRhel1yCud || 0, instance_b.monthRhel1yCud || 0) %]
<td class="currency">[% instance_b.monthRhel1yCud %]</td>
</tr>
<tr>
<th>Red Hat Enterprise Linux w. 3 year CUD</th>
<td class="currency table-active">[% instance_a.monthRhel3yCud %]</td>
[% tableCompareCosts(instance_a.monthRhel3yCud || 0, instance_b.monthRhel3yCud || 0) %]
<td class="currency">[% instance_b.monthRhel3yCud %]</td>
</tr>
<tr>
<th>SUSE Linux Enterprise Server for SAP</th>
<td class="currency table-active">[% instance_a.monthSlesSap %]</td>
[% tableCompareCosts(instance_a.monthSlesSap || 0, instance_b.monthSlesSap || 0) %]
<td class="currency">[% instance_b.monthSlesSap %]</td>
</tr>
<tr>
<th>SUSE Linux Enterprise Server for SAP w. 1 year CUD</th>
<td class="currency table-active">[% instance_a.monthSlesSap1yCud %]</td>
[% tableCompareCosts(instance_a.monthSlesSap1yCud || 0, instance_b.monthSlesSap1yCud || 0) %]
<td class="currency">[% instance_b.monthSlesSap1yCud %]</td>
</tr>
<tr>
<th>SUSE Linux Enterprise Server for SAP w. 3 year CUD</th>
<td class="currency table-active">[% instance_a.monthSlesSap3yCud %]</td>
[% tableCompareCosts(instance_a.monthSlesSap3yCud || 0, instance_b.monthSlesSap3yCud || 0) %]
<td class="currency">[% instance_b.monthSlesSap3yCud %]</td>
</tr>
<tr>
<th>Red Hat Enterprise Linux for SAP</th>
<td class="currency table-active">[% instance_a.monthRhelSap %]</td>
[% tableCompareCosts(instance_a.monthRhelSap || 0, instance_b.monthRhelSap || 0) %]
<td class="currency">[% instance_b.monthRhelSap %]</td>
</tr>
<tr>
<th>Red Hat Enterprise Linux for SAP w. 1 year CUD</th>
<td class="currency table-active">[% instance_a.monthRhelSap1yCud %]</td>
[% tableCompareCosts(instance_a.monthRhelSap1yCud || 0, instance_b.monthRhelSap1yCud || 0) %]
<td class="currency">[% instance_b.monthRhelSap1yCud %]</td>
</tr>
<tr>
<th>Red Hat Enterprise Linux for SAP w. 3 year CUD</th>
<td class="currency table-active">[% instance_a.monthRhelSap3yCud %]</td>
[% tableCompareCosts(instance_a.monthRhelSap3yCud || 0, instance_b.monthRhelSap3yCud || 0) %]
<td class="currency">[% instance_b.monthRhelSap3yCud %]</td>
</tr>
</tbody>
</table>
</div> <!-- // table-responsive -->
</div> <!-- // col -->
</div> <!-- // row -->
<h2>Regions</h2>
<p>Costs for Google Compute Engine machine types [% instance_a.name %] and [% instance_b.name %] in Google Cloud regions in which the VMs are available.</p>
<div class="table-responsive">
<table
class="table table-sm table-hover table-bordered"
data-classes="table table-sm table-hover table-bordered"
data-toggle="table"
data-sort-name="name"
data-sort-order="asc"
data-sticky-header="true"
>
<thead>
<tr>
<th scope="col" colspan="2">Region</th>
<th scope="col" colspan="3">Hour</th>
<th scope="col" colspan="3">Spot</th>
<th scope="col" colspan="3">Month</th>
<th scope="col" colspan="3">1 year CUD</th>
<th scope="col" colspan="3">3 year CUD</th>
</tr>
<tr>
<th scope="col" data-field="name" data-sortable="true">Name</th>
<th scope="col">Location</th>
<!-- Hour -->
<th scope="col" class="table-active">[% instance_a.name %]</th>
<th scope="col"></th>
<th scope="col">[% instance_b.name %]</th>
<!-- Spot -->
<th scope="col" class="table-active">[% instance_a.name %]</th>
<th scope="col"></th>
<th scope="col">[% instance_b.name %]</th>
<!-- Month -->
<th scope="col" class="table-active">[% instance_a.name %]</th>
<th scope="col"></th>
<th scope="col">[% instance_b.name %]</th>
<!-- 1Y CUD -->
<th scope="col" class="table-active">[% instance_a.name %]</th>
<th scope="col"></th>
<th scope="col">[% instance_b.name %]</th>
<!-- 3Y CUD -->
<th scope="col" class="table-active">[% instance_a.name %]</th>
<th scope="col"></th>
<th scope="col">[% instance_b.name %]</th>
</tr>
</thead>
<tbody>
[% FOREACH region IN regions %]
<tr>
<td><a href="/[% region.name %].html" title="Show all machine types in region [% region.name %]">[% region.name %]</a></td>
<td>[% region.regionLocation %]</td>
<!-- Hour -->
[%-
costs_a = 0;
costs_b = 0;
FOREACH region_a IN regions_a;
IF region_a.region == region.name;
costs_a = region_a.hour;
END;
END;
FOREACH region_b IN regions_b;
IF region_b.region == region.name;
costs_b = region_b.hour;
END;
END;
-%]
[% IF costs_a %]
<td class="currency table-active" title="Costs per hour [% instance_a.name %] in [% region.name %]: [% costs_a %] USD"><a href="/[% region.name %]/[% instance_a.name %].html">[% costs_a %]</a></td>
[% ELSE %]
<td class="table-warning" title="Machine type [% instance_a.name %] is not available in the region [% region.name %]"><span class="text-muted">N.A.</span></td>
[% END %]
[% IF costs_a && costs_b %]
[% tableCompareCosts(costs_a || 0, costs_b || 0) %]
[% ELSE %]
<td class="table-warning"><span class="text-muted">-</span></td>
[% END %]
[% IF costs_b %]
<td class="currency" title="Costs per hour [% instance_b.name %] in [% region.name %]: [% costs_b %] USD"><a href="/[% region.name %]/[% instance_b.name %].html">[% costs_b %]</a></td>
[% ELSE %]
<td class="table-warning" title="Machine type [% instance_a.name %] is not available in the region [% region.name %]"><span class="text-muted">N.A.</span></td>
[% END %]
<!-- Spot -->
[%-
costs_a = 0;
costs_b = 0;
FOREACH region_a IN regions_a;
IF region_a.region == region.name;
costs_a = region_a.hourSpot;
END;
END;
FOREACH region_b IN regions_b;
IF region_b.region == region.name;
costs_b = region_b.hourSpot;
END;
END;
-%]
[% IF costs_a %]
<td class="currency table-active" title="Costs per hour [% instance_a.name %] in [% region.name %] with spot provisioning model (Spot VM): [% costs_a %] USD"><a href="/[% region.name %]/[% instance_a.name %].html">[% costs_a %]</a></td>
[% ELSE %]
<td class="table-warning" title="Machine type [% instance_a.name %] is not available in the region [% region.name %]"><span class="text-muted">N.A.</span></td>
[% END %]
[% IF costs_a && costs_b %]
[% tableCompareCosts(costs_a || 0, costs_b || 0) %]
[% ELSE %]
<td class="table-warning"><span class="text-muted">-</span></td>
[% END %]
[% IF costs_b %]
<td class="currency" title="Costs per hour [% instance_b.name %] in [% region.name %] with spot provisioning model (Spot VM): [% costs_b %] USD"><a href="/[% region.name %]/[% instance_b.name %].html">[% costs_b %]</a></td>
[% ELSE %]
<td class="table-warning" title="Machine type [% instance_a.name %] is not available in the region [% region.name %]"><span class="text-muted">N.A.</span></td>
[% END %]
<!-- Month -->
[%-
costs_a = 0;
costs_b = 0;
FOREACH region_a IN regions_a;
IF region_a.region == region.name;
costs_a = region_a.month;
END;
END;
FOREACH region_b IN regions_b;
IF region_b.region == region.name;
costs_b = region_b.month;
END;
END;
-%]
[% IF costs_a %]
<td class="text-nowrap table-active" title="Costs per month [% instance_a.name %] in [% region.name %]: [% costs_a %] USD">
<span class="currency"><a href="/[% region.name %]/[% instance_a.name %].html">[% costs_a %]</a></span>
[% badgeSud(instance_a) %]
</td>
[% ELSE %]
<td class="table-warning" title="Machine type [% instance_a.name %] is not available in the region [% region.name %]"><span class="text-muted">N.A.</span></td>
[% END %]
[% IF costs_a && costs_b %]
[% tableCompareCosts(costs_a || 0, costs_b || 0) %]
[% ELSE %]
<td class="table-warning"><span class="text-muted">-</span></td>
[% END %]
[% IF costs_b %]
<td class="text-nowrap" title="Costs per month [% instance_b.name %] in [% region.name %]: [% costs_b %] USD">
<span class="currency"><a href="/[% region.name %]/[% instance_b.name %].html">[% costs_b %]</a></span>
[% badgeSud(instance_b) %]
</td>
[% ELSE %]
<td class="table-warning" title="Machine type [% instance_a.name %] is not available in the region [% region.name %]"><span class="text-muted">N.A.</span></td>
[% END %]
<!-- 1Y CUD -->
[%-
costs_a = 0;
costs_b = 0;
FOREACH region_a IN regions_a;
IF region_a.region == region.name;
costs_a = region_a.month1yCud;
END;
END;
FOREACH region_b IN regions_b;
IF region_b.region == region.name;
costs_b = region_b.month1yCud;
END;
END;
-%]
[% IF costs_a %]
<td class="table-active" title="Costs per month [% instance_a.name %] in [% region.name %] with 1Y CUD: [% costs_a %] USD">
<span class="currency"><a href="/[% region.name %]/[% instance_a.name %].html">[% costs_a %]</a></span>
</td>
[% ELSE %]
<td class="table-warning" title="Machine type [% instance_a.name %] is not available in the region [% region.name %]"><span class="text-muted">N.A.</span></td>
[% END %]
[% IF costs_a && costs_b %]
[% tableCompareCosts(costs_a || 0, costs_b || 0) %]
[% ELSE %]
<td class="table-warning"><span class="text-muted">-</span></td>
[% END %]
[% IF costs_b %]
<td title="Costs per month [% instance_b.name %] in [% region.name %] with 1Y CUD: [% costs_b %] USD">
<span class="currency"><a href="/[% region.name %]/[% instance_b.name %].html">[% costs_b %]</a></span>
</td>
[% ELSE %]
<td class="table-warning" title="Machine type [% instance_a.name %] is not available in the region [% region.name %]"><span class="text-muted">N.A.</span></td>
[% END %]
<!-- 3Y CUD -->
[%-
costs_a = 0;
costs_b = 0;
FOREACH region_a IN regions_a;
IF region_a.region == region.name;
costs_a = region_a.month3yCud;
END;
END;
FOREACH region_b IN regions_b;
IF region_b.region == region.name;
costs_b = region_b.month3yCud;
END;
END;
-%]
[% IF costs_a %]
<td class="table-active" title="Costs per month [% instance_a.name %] in [% region.name %] with 3Y CUD: [% costs_a %] USD">
<span class="currency"><a href="/[% region.name %]/[% instance_a.name %].html">[% costs_a %]</a></span>
</td>
[% ELSE %]
<td class="table-warning" title="Machine type [% instance_a.name %] is not available in the region [% region.name %]"><span class="text-muted">N.A.</span></td>
[% END %]
[% IF costs_a && costs_b %]
[% tableCompareCosts(costs_a || 0, costs_b || 0) %]
[% ELSE %]
<td class="table-warning"><span class="text-muted">-</span></td>
[% END %]
[% IF costs_b %]
<td title="Costs per month [% instance_b.name %] in [% region.name %] with 3Y CUD: [% costs_b %] USD">
<span class="currency"><a href="/[% region.name %]/[% instance_b.name %].html">[% costs_b %]</a></span>
</td>
[% ELSE %]
<td class="table-warning" title="Machine type [% instance_a.name %] is not available in the region [% region.name %]"><span class="text-muted">N.A.</span></td>
[% END %]
</tr>
[% END %]
</tbody>
</table>
</div> <!-- // table-responsive -->
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/config.tt2
================================================
[%-
site = {
url => 'https://gcloud-compute.com',
github = {
repo => 'https://github.com/Cyclenerd/google-cloud-compute-machine-types',
issues => 'https://github.com/Cyclenerd/google-cloud-compute-machine-types/issues',
},
agGrid = {
css => 'https://cdn.jsdelivr.net/npm/ag-grid-community@31.0.3/styles/ag-grid.min.css'
theme => 'https://cdn.jsdelivr.net/npm/ag-grid-community@31.0.3/styles/ag-theme-balham.min.css'
js => 'https://cdn.jsdelivr.net/npm/ag-grid-community@31.0.3/dist/ag-grid-community.min.noStyle.js'
},
agCharts = {
js => 'https://cdn.jsdelivr.net/npm/ag-charts-community@9.0.2/dist/umd/ag-charts-community.min.js'
}
jQuery = {
js => 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js'
},
bootstrap = {
css => 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/css/bootstrap.min.css'
js => 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.2.3/js/bootstrap.bundle.min.js'
},
bootstrapTable = {
css => 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.22.2/bootstrap-table.min.css'
js => 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.22.2/bootstrap-table.min.js'
},
bootstrapTableStickyHeader = {
css => 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.22.2/extensions/sticky-header/bootstrap-table-sticky-header.min.css'
js => 'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-table/1.22.2/extensions/sticky-header/bootstrap-table-sticky-header.min.js'
},
leaflet = {
css => 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css'
js => 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js'
},
};
PROCESS macros.tt2;
-%]
================================================
FILE: build/src/disk.tt2
================================================
[%- PROCESS header.tt2 -%]
<h1>Google Compute Engine Disk Type [% disk.name %]</h1>
[%-
minDiskSize = 10;
IF disk.name == 'pd-extreme'; minDiskSize = 500; END;
IF disk.name == 'local-ssd'; minDiskSize = 375; END;
-%]
<blockquote class="blockquote">
<p>[% IF disk.description %][% disk.description %], [% END %]<mark>minimum capacity per disk [% minDiskSize %] GB</mark>.</p>
</blockquote>
<p>Costs and pricing for Google Compute Engine disk type [% disk.name %] in Google Cloud regions in which the disk is available.</p>
<div class="table-responsive">
<table
class="table table-hover table-bordered"
data-toggle="table"
data-sort-name="region"
data-sort-order="asc"
data-sortable="true"
data-sticky-header="true"
>
<thead>
<tr>
<th scope="col" data-field="region" data-sortable="true">Region</th>
<th scope="col">Location</th>
<th scope="col" data-sortable="true">#Zones</th>
<!-- Costs -->
<th scope="col" data-sortable="true">1 GB</th>
<th scope="col" data-sortable="true">10 GB</th>
<th scope="col" data-sortable="true">375 GB</th>
<th scope="col" data-sortable="true">500 GB</th>
</tr>
</thead>
<tbody>
[% FOREACH region IN regions %]
<tr>
<td>
<a
href="/[% region.name %].html"
title="Google Compute Engine disk type [% disk.name %] in Google Cloud region [% region.name %]">
[% region.name %]
</a>
</td>
<td>[% IF region.regionLocation %][% region.regionLocation %][% ELSE %]<span class="text-muted">?</span>[% END %]</td>
<td [% IF region.zoneCount < 1%]class="table-danger"[% END%] title="Available [% region.zoneCount %] zone[% IF region.zoneCount > 1 %]s[% END %] in region [% region.name %]">[% IF region.zoneCount %][% region.zoneCount %][% ELSE %]<span class="text-muted">?</span>[% END %]</td>
<!-- Costs -->
[% IF region.monthGb %]
<td title="Costs for 1 GB [% disk.name %] per month: [% region.monthGb %] USD" class="currency">[% region.monthGb %]</td>
<td title="Costs for 10 GB [% disk.name %] per month: [% region.monthGb %] USD" class="currency">[% region.monthGb*10 FILTER format("%.2f") %]</td>
<td title="Costs for 375 GB [% disk.name %] per month: [% region.monthGb %] USD" class="currency">[% region.monthGb*375 FILTER format("%.2f") %]</td>
<td title="Costs for 500 GB [% disk.name %] per month: [% region.monthGb %] USD" class="currency">[% region.monthGb*500 FILTER format("%.2f") %]</td>
[% ELSE %]
<td>???</td>
<td>???</td>
<td>???</td>
<td>???</td>
[% END %]
</tr>
[% END %]
</tbody>
</table>
</div><!-- table-responsive -->
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/diskpricing.tt2
================================================
[%- PROCESS header.tt2 -%]
[%- PROCESS regions_header.tt2 -%]
<h1>Persistent Disk Pricing in Google Cloud Regions</h1>
<blockquote class="blockquote">
<p>
Each Google Compute Engine machine type (VM instance) has at least one boot disk attached to it.
Each disk incurs a cost, described in this overview.
Breakdown by price per GB and minimum capacity per disk.
</p>
</blockquote>
<p>
<a class="btn btn-success" href="/map.html" role="button">🗺️ Region Map</a>
<a class="btn btn-secondary" href="https://gcping.com/" role="button" rel="nofollow" title="Measure your latency to Google Cloud regions">⏱️ Ping</a>
</p>
<div class="table-responsive">
<table
class="table table-sm table-hover table-bordered"
data-classes="table table-sm table-hover table-bordered"
data-toggle="table"
data-sort-name="name"
data-sort-order="asc"
data-sortable="true"
data-sticky-header="true"
>
<thead>
<tr>
<th scope="col" colspan="2">Region</th>
<th scope="col">Zones</th>
<th scope="col" colspan="2" title="Efficient and reliable block storage. Minimum capacity per disk: 10 GB">Standard</th>
<th scope="col" colspan="2" title="Cost-effective and reliable block storage. Minimum capacity per disk: 10 GB">Balanced</th>
<th scope="col" colspan="2" title="Fast and reliable block storage. Minimum capacity per disk: 10 GB">SSD</th>
<th scope="col" colspan="2" title="Highest performance persistent block storage option. Minimum capacity per disk: 500 GB">Extreme</th>
<th scope="col" colspan="2" title="High performance local block storage. Minimum and maximum capacity per disk: 375 GB">Local SSD</th>
</tr>
<tr>
<!-- Region -->
<th scope="col" data-field="name" data-sortable="true">Name</th>
<th scope="col" data-sortable="true">Location</th>
<!-- Zones -->
<th scope="col" data-sortable="true">#</th>
<!-- Standard -->
<th scope="col" data-sortable="true">1 GB</th>
<th scope="col" data-sortable="true">10 GB</th>
<!-- Balanced -->
<th scope="col" data-sortable="true">1 GB</th>
<th scope="col" data-sortable="true">10 GB</th>
<!-- SSD -->
<th scope="col" data-sortable="true">1 GB</th>
<th scope="col" data-sortable="true">10 GB</th>
<!-- Extreme -->
<th scope="col" data-sortable="true">1 GB</th>
<th scope="col" data-sortable="true">500 GB</th>
<!-- Local SSD -->
<th scope="col" data-sortable="true">1 GB</th>
<th scope="col" data-sortable="true">375 GB</th>
</tr>
</thead>
<tbody>
[% FOREACH region IN disks_regions %]
<tr>
<td><a href="/[% region.name %].html" title="Google Cloud region [% region.name %]">[% region.name %]</a></td>
<td>[% IF region.regionLocation %][% region.regionLocation %][% ELSE %]<span class="text-muted">?</span>[% END %]</td>
<td>[% region.zoneCount %]</td>
<!-- Standard -->
[% IF region.standard %]
<td title="Costs for 1 GB standard persistent disk per month in region [% region.name %]: [% region.standard %] USD" class="currency">[% region.standard %]</td>
<td title="Costs for 10 GB standard persistent disk per month in region [% region.name %]: [% region.standard*10 FILTER format("%.2f") %] USD" class="currency">[% region.standard*10 FILTER format("%.2f") %]</td>
[% ELSE %]
<td class="table-warning">-</td>
<td class="table-warning">-</td>
[% END %]
<!-- Balanced -->
[% IF region.balanced %]
<td title="Costs for 1 GB balanced persistent disk per month in region [% region.name %]: [% region.balanced %] USD" class="currency">[% region.balanced %]</td>
<td title="Costs for 10 GB balanced persistent disk per month in region [% region.name %]: [% region.balanced*10 FILTER format("%.2f") %] USD" class="currency">[% region.balanced*10 FILTER format("%.2f") %]</td>
[% ELSE %]
<td class="table-warning">-</td>
<td class="table-warning">-</td>
[% END %]
<!-- SSD -->
[% IF region.ssd %]
<td title="Costs for 1 GB SSD persistent disk per month in region [% region.name %]: [% region.ssd %] USD" class="currency">[% region.ssd %]</td>
<td title="Costs for 10 GB SSD persistent disk per month in region [% region.name %]: [% region.ssd*10 FILTER format("%.2f") %] USD" class="currency">[% region.ssd*10 FILTER format("%.2f") %]</td>
[% ELSE %]
<td class="table-warning">-</td>
<td class="table-warning">-</td>
[% END %]
<!-- Extreme -->
[% IF region.extreme %]
<td title="Costs for 1 GB extreme persistent disk per month in region [% region.name %]: [% region.extreme %] USD" class="currency">[% region.extreme %]</td>
<td title="Costs for 500 GB extreme persistent disk per month in region [% region.name %]: [% region.extreme*500 FILTER format("%.2f") %] USD" class="currency">[% region.extreme*500 FILTER format("%.2f") %]</td>
[% ELSE %]
<td class="table-warning">-</td>
<td class="table-warning">-</td>
[% END %]
<!-- Local SSD -->
[% IF region.local %]
<td title="Costs for 1 GB local SSD disk per month in region [% region.name %]: [% region.local %] USD" class="currency">[% region.local %]</td>
<td title="Costs for 375 GB local SSD disk per month in region [% region.name %]: [% region.local*375 FILTER format("%.2f") %] USD" class="currency">[% region.local*375 FILTER format("%.2f") %]</td>
[% ELSE %]
<td class="table-warning">-</td>
<td class="table-warning">-</td>
[% END %]
</tr>
[% END %]
</tbody>
</table>
</div><!-- table-responsive -->
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/disks.js
================================================
const options = {
container: document.getElementById('myChart'),
autoSize: true,
title: {
text: 'Performance by Disk Size',
enabled: false
},
data: [
{
size: '10 GB',
// HDD
hdd_read: 0,
hdd_write: 0,
// SSD
ssd_read: 4.8,
ssd_write: 4.8
},
{
size: '32 GB',
// HDD
hdd_read: 3,
hdd_write: 3,
// SSD
ssd_read: 15,
ssd_write: 15
},
{
size: '64 GB',
// HDD
hdd_read: 7,
hdd_write: 7,
// SSD
ssd_read: 30,
ssd_write: 30
},
{
size: '128 GB',
// HDD
hdd_read: 15,
hdd_write: 15,
// SSD
ssd_read: 61,
ssd_write: 61
},
{
size: '256 GB',
// HDD
hdd_read: 30,
hdd_write: 30,
// SSD
ssd_read: 122,
ssd_write: 122
},
{
size: '500 GB',
// HDD
hdd_read: 60,
hdd_write: 60,
// SSD
ssd_read: 240,
ssd_write: 240
},
{
size: '1 TB',
// HDD
hdd_read: 120,
hdd_write: 120,
// SSD
ssd_read: 480,
ssd_write: 480
},
{
size: '2 TB',
// HDD
hdd_read: 245,
hdd_write: 245,
// SSD
ssd_read: 983,
ssd_write: 983
},
{
size: '4 TB',
// HDD
hdd_read: 480,
hdd_write: 400,
// SSD
ssd_read: 1200,
ssd_write: 1200
},
{
size: '5 TB',
// HDD
hdd_read: 600,
hdd_write: 400,
// SSD
ssd_read: 1200,
ssd_write: 1200
},
{
size: '8 TB',
// HDD
hdd_read: 983,
hdd_write: 400,
// SSD
ssd_read: 1200,
ssd_write: 1200
},
{
size: '10 TB',
// HDD
hdd_read: 1200,
hdd_write: 400,
// SSD
ssd_read: 1200,
ssd_write: 1200
}
],
series: [
{
xKey: 'size',
yKey: 'hdd_write',
yName: 'Standard Write (MBps)',
stroke: '#20c997',
marker: {
shape: 'square',
fill: '#20c997',
stroke: '#20c997',
},
},
{
xKey: 'size',
yKey: 'hdd_read',
yName: 'Standard Read (MBps)',
stroke: '#198754',
marker: {
shape: 'square',
fill: '#198754',
stroke: '#198754',
},
},
{
xKey: 'size',
yKey: 'ssd_write',
yName: 'SSD Write (MBps)',
stroke: '#6610f2',
marker: {
shape: 'circle',
fill: '#6610f2',
stroke: '#6610f2',
},
},
{
xKey: 'size',
yKey: 'ssd_read',
yName: 'SSD Read (MBps)',
stroke: '#6f42c1',
marker: {
shape: 'circle',
fill: '#6f42c1',
stroke: '#6f42c1',
},
},
],
axes: [
{
type: 'category',
position: 'bottom',
title: {
text: 'Disk Size',
enabled: false,
},
},
{
type: 'number',
position: 'left',
title: {
text: 'Sustained throughput (MBps)',
enabled: false,
},
label: {
formatter: function (params) { return params.value + ' MBps'; },
},
},
],
legend: {
enabled: true,
position: 'bottom'
},
};
agCharts.AgChart.create(options);
================================================
FILE: build/src/disks.tt2
================================================
[%- PROCESS header.tt2 -%]
<h1>Google Compute Engine Persistent Disk Types</h1>
<blockquote class="blockquote">
<p>
Google Compute Engine offers <mark>[% disks.size %]</mark> disk types for your instances.
Each of the following disk types has unique price and performance characteristics.
</p>
</blockquote>
<div class="table-responsive">
<table
class="table table-hover table-bordered"
data-toggle="table"
data-sort-name="1gb"
data-sort-order="asc"
data-sortable="true"
data-sticky-header="false"
>
<thead>
<tr>
<th scope="col" colspan="3">Disk Type</th>
<th scope="col">Region</th>
<th scope="col" colspan="3">Costs (Avg. Region)</th>
</tr>
<tr>
<th scope="col" data-field="name" data-sortable="true">Name</th>
<th scope="col">Description</th>
<th scope="col" title="Minimum capacity per disk">Min. Disk Size</th>
<th scope="col" data-sortable="true">#</th>
<th scope="col" data-field="1gb" data-sortable="true">1 GB</th>
<th scope="col" data-sortable="true">10 GB</th>
<th scope="col" data-sortable="true">500 GB</th>
</tr>
</thead>
<tbody>
[%-
FOREACH disk IN disks;
minDiskSize = 10;
IF disk.name == 'pd-extreme'; minDiskSize = 500; END;
IF disk.name == 'local-ssd'; minDiskSize = 375; END;
-%]
<tr>
<td><a href="/[% disk.name %].html" title="Persistent disk type [% disk.name %]">[% disk.name %]</a></td>
<td>[% disk.description %]</td>
[% IF minDiskSize %]<td [% IF minDiskSize > 400 %]class="table-danger"[% ELSIF minDiskSize > 300 %]class="table-warning"[% END %]>[% minDiskSize %] GB</td>[% ELSE %]<td>???</td>[% END %]
<td>[% disk.regionCount %]</td>
[% IF disk.avgMonth %]
<td title="Avg. costs for 1 GB [% disk.name %] per month: [% disk.avgMonth %] USD" class="currency">[% disk.avgMonth %]</td>
<td title="Avg. costs for 10 GB [% disk.name %] per month: [% disk.avgMonth %] USD" class="currency">[% disk.avgMonth*10 FILTER format("%.2f") %]</td>
<td title="Avg. costs for 500 GB [% disk.name %] per month: [% disk.avgMonth %] USD" class="currency">[% disk.avgMonth*500 FILTER format("%.2f") %]</td>
[% ELSE %]
<td>???</td>
<td>???</td>
<td>???</td>
[% END %]
</tr>
[%- END -%]
</tbody>
</table>
</div> <!-- // table-responsive -->
<h2 class="mt-2">Performance by Disk Size</h2>
<p>
Persistent disk performance scales with the size of the disk and with the number of vCPUs on your Google Compute Engine VM instance.
The <a href="https://cloud.google.com/compute/docs/disks/performance" rel="nofollow"> Google documentation</a> explains the whole concept very detailed.
The following graphic is only meant to give a quick overview.
</p>
<div id="myChart" style="height: 400px"></div>
<script src="[% site.agCharts.js %]"></script>
<script src="/disks.js">
</script>
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/download.tt2
================================================
[%- PROCESS header.tt2 -%]
</div> <!-- // container-fluid -->
<div class="container">
<h1>Download</h1>
<p>
You can download a <a href="/machine-types-regions.csv?[% timestamp %]" download="machine-types-regions.csv">CSV</a> file ([% csvFileSize %] MB)
and <a href="/machine-types-regions.sql.gz?[% timestamp %]" download="machine-types-regions.sql.gz">SQL</a> export ([% sqlFileSize %] MB, gzip compressed) with all machine types, disk types, operating system images, Google Cloud regions and zones.
You can import and edit the CSV file to your favorite spreadsheet program (MS Excel, LibreOffice or Google Sheets).
You can import the SQL dump into your favorite database (like SQLite).
</p>
<h2>Spreadsheet</h2>
<p>Comma Separated Values (CSV) file with GCE machine types and Google Cloud regions.</p>
<p><a class="btn btn-primary" href="/machine-types-regions.csv?[% timestamp %]" download="machine-types-regions.csv">Download CSV ([% csvFileSize %] MB)</a><p>
<h2>Database</h2>
<p>Gzip compressed Structured Query Language (SQL) export with GCE machine types, disk types, operating system images, Google Cloud regions and zones.</p>
<p><a class="btn btn-primary" href="/machine-types-regions.sql.gz?[% timestamp %]" download="machine-types-regions.sql.gz">Download SQL ([% sqlFileSize %] MB)</a><p>
<h2>Command Line</h2>
<p>With the SQL export you can also do great queries using the command line (CLI).</p>
<pre class="bg-light"><code><span class="text-muted"># Download CSV file</span>
curl -O [% site.url %]/machine-types-regions.csv
<span class="text-muted"># Search CSV and count</span>
grep <span class="text-primary">'europe-west4'</span> < machine-types-regions.csv | wc -l
<span class="text-muted"># Download SQL export</span>
curl -O [% site.url %]/machine-types-regions.sql.gz
<span class="text-muted"># Decompress SQL export</span>
gzip -d machine-types-regions.sql.gz
<span class="text-muted"># Import SQL dump</span>
sqlite3 gce.db < machine-types-regions.sql
<span class="text-muted"># SQL query Google Cloud machine types (instances)</span>
sqlite3 gce.db <span class="text-primary">'SELECT name, vCpus, hour FROM instances WHERE vCpus >= 8 AND region LIKE "europe-west4" ORDER BY hour ASC LIMIT 5'</span></code></pre>
<p>Example SQL output:</p>
<pre class="bg-light"><code>e2-highcpu-8|8.0|0.21785232
n2d-highcpu-8|8.0|0.274688
e2-standard-8|8.0|0.29508816
n1-highcpu-8|8.0|0.3119968
n2-highcpu-8|8.0|0.315728</code></pre>
<h2>Open Source</h2>
<p>
Everything you see here is published as open source software and licensed under the Apache License (version 2.0).
You can find the source code on <a href="[% site.github.repo %]">GitHub</a>.
Any improvements and pull requests are welcome.
</p>
[%- PROCESS footer.tt2 -%]
================================================
FILE: build/src/favicon.tt2
================================================
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
================================================
FILE: build/src/footer.tt2
================================================
</div> <!-- // container -->
</main>
<footer class="footer py-3 bg-light mt-2">
<div class="container-fluid">
<p class="text-muted">
Copyright [% USE date; date.format(date.now, '%Y'); %] <a href="https://www.nkn-it.de/">Nils Knieling</a>
·
All rights reserved
</p>
<p class="text-muted">
The accuracy of the data is not guaranteed. Please <a href="[% site.github.issues %]">report issues</a> you see.
Portions of this webapp are modifications based on work created and shared by <a href="https://developers.google.com/readme/policies">Google</a>
and used according to terms described in the <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons 4.0 Attribution License</a>.
</p>
<p class="text-muted small">
Last Update: [% gmtime %] (GMT)
·
<a href="/imprint.html">Imprint</a>
·
<a href="https://www.nkn-it.de/dsgvo.html">Datenschutz</a>
</p>
</div> <!-- // container -->
</footer>
<script src="[% site.bootstrap.js %]"></script>
<script src="[% site.jQuery.js %]"></script>
<script src="[% site.bootstrapTable.js %]"></script>
<script src="[% site.bootstrapTableStickyHeader.js %]"></script>
<script src="/popin-min.js"></script>
<script>
if(!document.getElementById('i59UOEcRSLY1gwtC')){
const alertDiv = document.getElementById('pleaseDisableYourAdBlocker');
alertDiv.className = 'alert alert-danger mt-2';
alertDiv.role = 'alert';
alertDiv.innerHTML = `
<strong>Hi there! It looks like you're using an ad blocker.</strong>
I put a lot of heart and soul into keeping this site updated,
but the servers and coffee that power it aren't free!
Ads are the primary way I cover these costs and keep everything running for you.
Would you mind whitelisting this site?
It is a huge help.
Thank you for your support!
`;
}
</script>
</body>
</html>
================================================
FILE: build/src/gcosts.tt2
================================================
[%- PROCESS header.tt2 -%]
</div> <!-- // container-fluid -->
<div class="container">
<h1>Google Cloud Platform Pricing and Cost Calculator</h1>
<p>
Calculate estimated monthly costs of Google Cloud Platform products and resources on your local computer.
Optimized for DevOps, architects and engineers to quickly see a cost breakdown and compare different options upfront:
</p>
<ul>
<li>Mapping of resource usage is done in easy to learn YAML usage files</li>
<li>Price information is read from a local file</li>
<li>Calculation is done via <code>gcosts</code> CLI program</li>
<li>Calculated costs are saved in CSV file optimized for non-technical audience</li>
</ul>
<p>
Full control and no disclosure of any information and costs to third parties.
Everything is calculated on your local computer.
No need to have a connection to the Internet.
Everything tested and matched against the actual invoice in large Google Cloud migration projects.
<p>
<code>gcosts</code> works on various OS and terminals, including Linux, macOS and Windows.
</p>
<div class="row">
<div class="col-xl-4">
<p class="fw-bolder">1. Create YAML file</p>
<p><img src="/img/usage.png?[% timestamp %]" alt="Screenshot: Create YAML file" class="img-fluid"></p>
</div>
<div class="col-xl-4">
<p class="fw-bolder">2. Run gcosts CLI program</p>
<p><img src="/img/gcosts.png?[% timestamp %]" alt="Screenshot: Run gcosts CLI program" class="img-fluid"></p>
</div>
<div class="col-xl-4">
<p class="fw-bolder">3. Open CSV file</p>
<p><img src="/img/csv.png?[% timestamp %]" alt="Screenshot: Open CSV file" class="img-fluid"></p>
</div>
</div>
<h2>Download</h2>
<p>
The <code>gcosts</code> pricing and cost calculator is Open Source software and free to use.
You can find a detailed documentation and all download options on
<a href="https://github.com/Cyclenerd/google-cloud-pricing-cost-calculator#readme">GitHub</a>.
</p>
<p>
<a class="btn btn-lg btn-warning" href="https://github.com/Cyclenerd/google-cloud-pricing-cost-calculator#-quick-start">Linux</a>
<a class="btn btn-lg btn-dark" href="https://github.com/Cyclenerd/google-cloud-pricing-cost-calculator#-quick-start">macOS</a>
<a class="btn btn-lg btn-success" href="https://github.com/Cyclenerd/google-cloud-pricing-cost-calculator#-quick-start">Windows</a>
<p>
<h2>Awarded</h2>
<p>
This project was the winner of the
<a href="https://opensource.googleblog.com/2022/09/announcing-the-second-group-of-open-source-peer-bonus-winners-in-2022.html">Google Open Source Peer Bonus</a>
in 2022.
<p>
[%- PROCESS footer.tt2 -%]
================================================
FILE: build/src/gpu.tt2
================================================
[%- PROCESS header.tt2 -%]
[%- PROCESS instances_header.tt2 -%]
<h1>Google Compute Engine Machine Types with Graphics Processing Units (GPUs)</h1>
[%- countGpu = 0; FOREACH instance IN instances; IF instance.acceleratorCount && instance.acceleratorCount > 0; countGpu = countGpu + 1; END; END -%]
<blockquote class="blockquote">
<p>
There are <mark>[% countGpu %]</mark> Google Compute Engine machine types with graphics processing units (GPUs) available.
Not every GCE machine type with GPU is available in every Google Cloud region.
</p>
</blockquote>
<p><a class="btn btn-success" href="/grid.html?gpu=1" role="button">✅ Instance Picker with filter on GPUs</a></p>
<div class="table-responsive">
[%- PROCESS instances_tr.tt2; -%]
<table
class="table table-sm table-hover table-bordered"
data-classes="table table-sm table-hover table-bordered"
data-toggle="table"
data-sort-name="gpus"
data-sort-order="asc"
data-sortable="true"
data-sticky-header="true"
>
<thead>
<tr>
<th scope="col" colspan="7">Machine Type</th>
<!-- Regions -->
<th scope="col">Regions</th>
<!-- Costs -->
<th scope="col" colspan="5">Costs (Avg. Region)</th>
</tr>
<tr>
<th scope="col" data-sortable="true">Name</th>
<th scope="col" data-field="vcpu" data-sortable="true">vCPU</th>
<th scope="col" data-sortable="true">Base Clock</th>
<th scope="col" data-sortable="true">Memory</th>
<th scope="col" data-field="gpus" data-sortable="true">GPUs</th>
<th scope="col" data-sortable="true">Type</th>
<th scope="col"></th>
<!-- Regions -->
<th scope="col">#</th>
<!-- Costs -->
<th scope="col" data-sortable="true">Hour</th>
<th scope="col" data-sortable="true">Spot</th>
<th scope="col" data-sortable="true">Month</th>
<th scope="col" data-sortable="true">1Y CUD</th>
<th scope="col" data-sortable="true">3Y CUD</th>
</tr>
</thead>
<tbody>
[%- FOREACH instance IN instances; IF instance.acceleratorCount && instance.acceleratorCount > 0; -%]
<tr>
<td><a href="[% instance.name %].html" title="Google Compute Engine machine type [% instance.name %]">[% instance.name %]</a></td>
<td class="text-nowrap">[% instance.vCpus %][% badgeSharedCpu(instance) %]</td>
<td class="frequency" title="CPU base clock frequency: [% instance.cpuBaseClock %] GHz">[% instance.cpuBaseClock %]</td>
<td class="memory" title="Random-access memory: [% instance.memoryGB %] GB">[% instance.memoryGB %]</td>
<td title="Accelerator (GPUs): [% instance.acceleratorCount %]">[% instance.acceleratorCount %]</td>
<td title="Accelerator Type: [% instance.acceleratorType %]">[% instance.acceleratorType %]</td>
<td>
[% badgeCpuManufactur(instance) %]
[% badgeSpot(instance) %]
[% badgeSud(instance) %]
[% badgeLocalSsd(instance) %]
</td>
<!-- Regions -->
<td>[% instance.regionCount %]</td>
<!-- Costs -->
<td class="currency" title="[% instance.name %] avg. per hour: [% instance.avgHour %] USD">[% instance.avgHour %]</td>
<td class="currency" title="[% instance.name %] avg. costs per hour with spot provisioning model (Spot VM): [% instance.avgHourSpot %] USD">[% instance.avgHourSpot %]</td>
<td class="currency" title="[% instance.name %] avg. costs per month: [% instance.avgMonth %] USD[% IF instance.sud %] with sustained use discounts (SUD) applied[% END %]">[% instance.avgMonth %]</td>
<td class="currency" title="[% instance.name %] avg. per month w. 1Y CUD: [% instance.avgMonth1yCud %] USD">[% instance.avgMonth1yCud %]</td>
<td class="currency" title="[% instance.name %] avg. per month w. 3Y CUD: [% instance.avgMonth3yCud %] USD">[% instance.avgMonth3yCud %]</td>
</tr>
[% END; END; %]
</tbody>
</table>
</div> <!-- // table-responsive -->
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/grid.tt2
================================================
<!doctype html>
<html lang="en">
<head>
<title>GCE Instance Picker</title>
<link rel="canonical" href="[% site.url %]/grid.html">
[% PROCESS favicon.tt2 %]
<link rel="stylesheet" href="[% site.agGrid.css %]">
<link rel="stylesheet" href="[% site.agGrid.theme %]">
<style>
html { width: 100%; height: 100%; }
body { width: 100%; height: 100%; margin: 0; padding: 0; }
.frequency::after { content: " GHz"; }
.currency::before { content: "$"; }
.percent::after { content: "%"; }
.bandwidth::after { content: " Gbps"; }
.diskSize::after { content: " TB"; }
.memory::after { content: " GB"; }
.warning::before { content: "⚠️ "; }
.sharedCpu::after { content: " (shared)"; }
</style>
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<script src="[% site.agGrid.js %]"></script>
</head>
<body>
<div id="myGrid" class="ag-theme-balham" style="height: 100%; width:100%"></div>
<script src="main.js?[% timestamp %]"></script>
</body>
</html>
================================================
FILE: build/src/hana.tt2
================================================
[%- PROCESS header.tt2 -%]
[%- PROCESS instances_header.tt2 -%]
<h1>Certified for SAP HANA on Google Cloud Platform</h1>
[%- countSAP = 0; FOREACH instance IN instances; IF instance.hana; countSAP = countSAP + 1; END; END -%]
<blockquote class="blockquote">
<p>
There are <mark>[% countSAP %]</mark> Google Compute Engine machine types certified for SAP HANA on Google Cloud Platform.
Not every certified Google Cloud VM is available in every region.
</p>
</blockquote>
<p><a class="btn btn-success" href="/grid.html?hana=1" role="button">✅ Instance Picker with filter on SAP HANA</a></p>
<div class="table-responsive">
<table
class="table table-sm table-hover table-bordered"
data-classes="table table-sm table-hover table-bordered"
data-toggle="table"
data-sort-name="vcpu"
data-sort-order="asc"
data-sortable="true"
data-sticky-header="true"
>
<thead>
<tr>
<th scope="col" colspan="6">Machine Type</th>
<th scope="col">Regions</th>
<th scope="col" colspan="4">Costs (Avg. Region)</th>
<th scope="col" colspan="2">OS with 3Y CUD</th>
</tr>
<tr>
<th scope="col" data-sortable="true">Name</th>
<th scope="col" data-field="vcpu" data-sortable="true">vCPU</th>
<th scope="col" data-sortable="true">Base Clock</th>
<th scope="col" data-sortable="true">Memory</th>
<th scope="col" data-sortable="true">SAPS</th>
<th scope="col"></th>
<th scope="col">#</th>
<!-- Costs -->
<th scope="col" data-sortable="true">Hour</th>
<th scope="col" data-sortable="true">Month</th>
<th scope="col" data-sortable="true">1Y CUD</th>
<th scope="col" data-sortable="true">3Y CUD</th>
<!-- OS -->
<th scope="col">SLES for SAP</th>
<th scope="col">RHEL for SAP</th>
</tr>
</thead>
<tbody>
[% FOREACH instance IN instances; IF instance.hana; %]
<tr>
<td><a href="[% instance.name %].html" title="Google Compute Engine machine type [% instance.name %]">[% instance.name %]</a></td>
<td class="text-nowrap">[% instance.vCpus %][% badgeSharedCpu(instance) %]</td>
<td class="frequency" title="CPU base clock frequency: [% instance.cpuBaseClock %] GHz">[% instance.cpuBaseClock %]</td>
<td class="memory" title="Random-access memory: [% instance.memoryGB %] GB">[% instance.memoryGB %]</td>
<td title="SAP Standard Benchmark: [% instance.saps %]">[% instance.saps %]</td>
<td>
[% badgeCpuManufactur(instance) %]
[% badgeSpot(instance) %]
[% badgeSud(instance) %]
[% badgeLocalSsd(instance) %]
</td>
<td>[% instance.regionCount %]</td>
<!-- Costs -->
<td class="currency" title="[% instance.name %] avg. per hour: [% instance.avgHour %] USD">[% instance.avgHour %]</td>
<td class="currency" title="[% instance.name %] avg. costs per month: [% instance.avgMonth %] USD[% IF instance.sud %] with sustained use discounts (SUD) applied[% END %]">[% instance.avgMonth %]</td>
<td class="currency" title="[% instance.name %] avg. per month w. 1Y CUD: [% instance.avgMonth1yCud %] USD">[% instance.avgMonth1yCud %]</td>
<td class="currency" title="[% instance.name %] avg. per month w. 3Y CUD: [% instance.avgMonth3yCud %] USD">[% instance.avgMonth3yCud %]</td>
<!-- OS -->
<td class="currency" title="[% instance.name %] license costs for SUSE Linux Enterprise Server for SAP with 3 year CUD: [% instance.monthSlesSap3yCud %] USD">[% instance.monthSlesSap3yCud %]</td>
<td class="currency" title="[% instance.name %] license costs for Red Hat Enterprise Linux for SAP with 3 year CUD: [% instance.monthRhelSap3yCud %] USD">[% instance.monthRhelSap3yCud %]</td>
</tr>
[% END; END; %]
</tbody>
</table>
</div> <!-- // table-responsive -->
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/header.tt2
================================================
<!doctype html>
<html lang="en">
<head>
[% PROCESS meta.tt2; %]
[% PROCESS favicon.tt2 %]
<link rel="stylesheet" href="[% site.bootstrap.css %]">
<link rel="stylesheet" href="[% site.bootstrapTable.css %]">
<link rel="stylesheet" href="[% site.bootstrapTableStickyHeader.css %]">
<style>
.frequency::after { content: " GHz"; }
.currency::before { content: "$"; }
.bandwidth::after { content: " Gbps"; }
.diskSize::after { content: " TB"; }
.memory::after { content: " GB"; }
</style>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-7267449040388963" crossorigin="anonymous"></script>
</head>
<body>
<header>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand mb-0 h1" href="/">
<span class="d-none d-lg-block">Google Cloud Platform 💸 Pricing</span>
<span class="d-lg-none">GCP 💸 Pricing</span>
</a>
<ul class="navbar-nav me-auto mb-2 mb-lg-0 d-none d-lg-block">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">More Tools</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="https://gcloud-iam.nkn-it.de/">Google Cloud Identity and Access Management (IAM)</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="https://aws-pricing.com/">Amazon EC2 Instance Type Comparison</a></li>
<li><a class="dropdown-item" href="https://ami.nkn-it.de/">Amazon Machine Images (AMIs)</a></li>
</ul>
</li>
</ul>
<div class="text-end">
<div class="d-none d-lg-block">
<a class="btn btn-success" href="/grid.html" role="button">✅ Instance Picker</a>
<a class="btn btn-primary" href="/download.html" role="button">💾 Download</a>
</div>
<div class="d-lg-none">
<a class="btn btn-success" href="/grid.html" role="button">✅</a>
<a class="btn btn-primary" href="/download.html" role="button">💾</a>
</div>
</div>
</div>
</nav>
</header>
<main>
<div class="container-fluid">
<div id="pleaseDisableYourAdBlocker"></div>
<div class="row mt-2 mb-2">
<div class="col">
<ul class="nav nav-tabs">
<li class="nav-item">
<a [% IF template.name == 'index.tt2' %]class="nav-link active" aria-current="page"[% ELSE %]class="nav-link"[% END %] href="/">👋 Hi</a>
</li>
<li class="nav-item">
<a [%- IF
template.name == 'instance.tt2' ||
template.name == 'comparison.tt2' ||
template.name == 'vs.tt2' ||
template.name == 'instances.tt2' ||
template.name == 'intel.tt2' ||
template.name == 'amd.tt2' ||
template.name == 'arm.tt2' ||
template.name == 'sap.tt2' ||
template.name == 'hana.tt2'
-%]class="nav-link active" aria-current="page"[% ELSE %]class="nav-link"[% END %]
href="/instances.html">Machines</a>
</li>
<li class="nav-item">
<a [%- IF
template.name == 'disk.tt2' ||
template.name == 'disks.tt2'
-%]class="nav-link active" aria-current="page"[% ELSE %]class="nav-link"[% END %]
href="/disks.html">Disks</a>
</li>
<li class="nav-item">
<a [%- IF
template.name == 'images.tt2'
-%]class="nav-link active" aria-current="page"[% ELSE %]class="nav-link"[% END %]
href="/images.html">Images</a>
</li>
<li class="nav-item">
<a [%- IF
template.name == 'instance_in_region.tt2' ||
template.name == 'region.tt2' ||
template.name == 'regions.tt2' ||
template.name == 'diskpricing.tt2' ||
template.name == 'platforms.tt2'
-%]class="nav-link active" aria-current="page"[% ELSE %]class="nav-link"[% END %]
href="/regions.html">Regions</a>
</li>
<li class="nav-item">
<a [%- IF
template.name == 'gcosts.tt2'
-%]class="nav-link active" aria-current="page"[% ELSE %]class="nav-link"[% END %]
href="/gcosts.html">Calculator</a>
</li>
</ul>
</div> <!-- // col -->
</div> <!-- // row -->
================================================
FILE: build/src/images.tt2
================================================
[%- PROCESS header.tt2 -%]
<h1>Google Compute Engine Operating System Images</h1>
<blockquote class="blockquote">
<p>
Compute Engine offers many preconfigured public images that have compatible <mark>Linux, UNIX or Windows operating systems</mark>.
Most images are free of charge.
Premium images (SLES, RHEL, Windows) add additional cost to your instances.
You can see the costs in the <a href="/instances.html">machine type</a> overview.
</p>
</blockquote>
<ul class="nav nav-pills" role="tablist">
[% FOREACH project IN image_projects %]
<li class="nav-item" role="presentation">
<button
class="nav-link[% IF project.name == 'debian-cloud' %] active[% END %]"
aria-selected="[% IF project.name == 'debian-cloud' %]true[% ELSE %]false[% END %]"
id="pills-[% project.name %]-tab"
data-bs-toggle="pill"
data-bs-target="#[% project.name %]"
type="button"
role="tab"
aria-controls="[% project.name %]">[% imageProjectName(project.name) %]</button>
</li>
[% END %]
</ul>
<div class="tab-content">
[% FOREACH project IN image_projects %]
<div
class="tab-pane[% IF project.name == 'debian-cloud' %] active[% END %]"
id="[% project.name %]"
role="tabpanel"
aria-labelledby="pills-[% project.name %]-tab">
<h2>[% imageProjectName(project.name) %] <small class="text-muted">[% project.name %]</small></h2>
<p>Image project: <code>[% project.name %]</code></p>
<div class="table-responsive">
<table class="table table-sm table-hover table-bordered">
<thead>
<tr>
<th>Image Family</th>
<th title="Most recent image name">Latest Image</th>
<th>Description</th>
<th title="Minimum persistent boot disk size">Min. Disk Size</th>
<th>Creation</th>
</tr>
</thead>
<tbody>
[% FOREACH family IN image_famlies; IF family.project == project.name; %]
<tr>
<td>[% family.name %]</td>
<td>
[% family.image %]
[% badgeImageArch(family.architecture) %]
</td>
<td>[% IF family.description %][% family.description %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
<td>[% family.diskSizeGb %] GB</td>
<td>[% family.creation | replace('T.+$','') %]</td>
</tr>
[% END; END; %]
</tbody>
</table>
</div><!-- table-responsive -->
<p>Google Cloud CLI:</p>
<script>
function copy[% project.name.remove('-') %]() {
var cli = document.getElementById("cli[% project.name.remove('-') %]").innerText;
navigator.clipboard.writeText(cli);
}
</script>
<div class="position-relative">
<div class="position-absolute top-0 end-0"><button type="button" class="btn btn-outline-primary btn-sm" onclick="copy[% project.name.remove('-') %]();" title="Copy to clipboard">Copy</button></div>
<pre class="bg-light"><code id="cli[% project.name.remove('-') %]"><span class="text-muted"># Create VM instance with [% imageProjectName(project.name) %] operating system boot disk</span>
<span class="text-muted"># Name: 'vm-[% project.name %]'</span>
<span class="text-muted"># Machine type: 'e2-micro'</span>
<span class="text-muted"># Zone: 'us-central1-a'</span>
gcloud compute instances create vm-[% project.name %] \
--machine-type=<span class="text-primary">'e2-micro'</span> \
--zone=<span class="text-primary">'us-central1-a'</span> \
--image-project=<span class="text-primary">'[% project.name %]'</span> \
--image-family=<span class="text-primary">'ADD_IMAGE_FAMILY_HERE'</span></code></pre>
</div> <!-- // position-relative -->
</div> <!-- // tab-pane -->
[% END %]
</div>
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/img/favicon/README.txt
================================================
This favicon was generated using the following graphics from Twitter Twemoji:
- Graphics Title: 1f4b8.svg
- Graphics Author: Copyright 2020 Twitter, Inc and other contributors (https://github.com/twitter/twemoji)
- Graphics Source: https://github.com/twitter/twemoji/blob/master/assets/svg/1f4b8.svg
- Graphics License: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
================================================
FILE: build/src/img/favicon/site.webmanifest
================================================
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
================================================
FILE: build/src/imprint.tt2
================================================
[%- PROCESS header.tt2 -%]
</div> <!-- // container-fluid -->
<div class="container">
<h1>Imprint</h1>
<p>🇩🇪 German law demands this.</p>
<p>
<address>
Nils Knieling<br>
Klabundeweg 14<br>
22359 Hamburg<br>
Deutschland
</address>
</p>
<p>Email: <code>nils [at] nkn-it (dot) de</code></p>
<p>Phone: + 49 (0) 40 2282 1390 (no support)</p>
<p>Umsatzsteuer-ID gemäß §27 a Umsatzsteuergesetz (VAT ID Number Germany): DE 279463785</p>
[%- PROCESS footer.tt2 -%]
================================================
FILE: build/src/index.tt2
================================================
[%- PROCESS header.tt2 -%]
</div> <!-- // container-fluid -->
<div class="container">
<h1>Google Compute Engine Machine Type Comparison</h1>
<p>
This webapp helps to find the optimal Google Compute Engine (GCE) machine type or instance in the many Google Cloud Platform (GCP) regions.
A lot of information has been collected from various Google Cloud websites and different sources.
</p>
<div class="p-5 mb-4 bg-light rounded-3">
<figure>
<blockquote class="blockquote">
<p>
I was tired of switching between different Google documentations to get all the information to find the best Google Compute Engine machine.
I have therefore merged all important information into one place.
Hope it helps you too.
</p>
</blockquote>
<figcaption class="blockquote-footer"><a href="https://github.com/Cyclenerd">Nils</a></figcaption>
</figure>
</div>
<h2>Machines</h2>
[%
intel = 0;
amd = 0;
arm = 0;
sap = 0;
hana = 0;
FOREACH instance IN instances;
IF instance.intel; intel = intel + 1; END;
IF instance.amd; amd = amd + 1; END;
IF instance.arm; arm = arm + 1; END;
IF instance.sap; sap = sap + 1; END;
IF instance.hana; hana = hana + 1; END;
END;
%]
<p>
<a href="/instances.html" title="All Google Conmpute Engine machine types">Here</a> you can find an overview of all <mark>[% instances.size %] different Google Compute Engine machine types</mark>.
You can also find the average costs per GCE machine type across all Google Cloud regions in this overview.
</p>
<p>
You have the choice between
<mark>[% intel %] machine types with <a href="/intel.html">Intel</a> CPU</mark>,
<mark>[% amd %] CPU machine types with <a href="/amd.html">AMD</a> CPU</mark> and
<mark>[% arm %] CPU machine types with <a href="/arm.html">Arm-based</a> processors</mark>.
[% sap %] machine types are certified for <a href="/sap.html">SAP application</a> and [% hana %] machine types are certified for <a href="/hana.html">SAP HANA</a> on Google Cloud.
</p>
<h2>Disks</h2>
<p>
<a href="/disks.html" title="Persistent Disk Types">Here</a> you can find an overview of <mark>[% disks.size %]</mark> different disk types for your instances.
</p>
<h2>Images</h2>
<p>
<a href="/images.html" title="Operating system images">Here</a> you can find an overview of many preconfigured public images that have compatible <mark>Linux, UNIX or Windows operating systems</mark>.
</p>
<h2>Regions</h2>
[%
regions_with_low_co2 = 0;
total_public_ip_addr = 0;
FOREACH region IN regions;
IF region.regionLowCo2; regions_with_low_co2 = regions_with_low_co2 + 1; END;
IF region.regionPublicIpv4Addr; total_public_ip_addr = total_public_ip_addr + region.regionPublicIpv4Addr; END;
END;
%]
<p>
<a href="/regions.html" title="All Google Cloud regions">Here</a> you can find an overview of all <mark>[% regions.size %] Google Cloud regions</mark> and the corresponding zones.
A total of <mark>[% total_public_ip_addr / 1000000 FILTER format("%d") %] million public IPv4 addresses</mark> are assigned to all Google Cloud Platform regions.
There is also a <a href="/map.html" title="Google Cloud Platform Region Map">map view</a> with all Google Cloud Platform regions.
You can also find the available Google Compute Engine machine types per GCE machine series (<a href="/platforms.html">CPU type and CPU plattform</a>) in this overview.
A cost overview of the <a href="/disks.html" title="Persistent disk pricing in Google Cloud regions">persistent disk types</a> in the regions can also be found in this section.
</p>
<p>
Of the [% regions.size %] regions, <mark>[% regions_with_low_co2 %] regions have a low carbon impact</mark>.
This means that this regions have a Google CFE% of at least 75%,
or, if CFE% information is not available, a grid carbon intensity of maximum 200 gCO2eq/kWh.
</p>
<p>
In total, you have the freedom to choose between <mark>[% instances_in_regions.size %] different combinations</mark> of Google Compute Engine machine types and Google Cloud regions.
For each combination the cost per hour, month with sustained use discounts (SUD), month with 1 year commitment (CUD) and price per month with 3 year commitment (CUD) was calculated.
The cost of paid "premium" operating system licenses, such as SUSE Linux Enterprise Server (SLES), Red Hat Enterprise Linux (RHEL) and Microsoft Windows Server, was also calculated.
</p>
<h2>Instance Picker</h2>
<p>
With the <a href="/grid.html">Instance Picker</a> you can quickly and easily compare all possible Google Compute Engine machine types and instances in all Google Cloud Platform regions.
</p>
<p>
You can set filters for each column and sort them.
Filters can be combined.
</p>
<p>
A good first filter is to set the preferred region.
You can also filter by parts of the region. Example <code>europe</code> to filter all machine types in Europe.
</p>
<h3>Filter</h3>
<p>
You can filter and sort all fields in the <a href="/grid.html">Instance Picker</a>.</p>
<div class="row">
<div class="col-xl-6">
<p>
Filter on region <code>europe-west4</code> and CPU base clock frequency greater than <code>3 GHz</code>:
<img src="/img/filter.png?[% timestamp %]" alt="Screenshot: Filter" class="img-fluid rounded">
</p>
</div>
<div class="col-xl-6">
<p>
Filter on region <code>europe-west4</code> and Memory greater than <code>30 GB</code> but also less than <code>60 GB</code>:
<img src="/img/combine-filter.png?[% timestamp %]" alt="Screenshot: Filter combined" class="img-fluid rounded">
</p>
</div>
</div>
<h3>Sort and more</h3>
<div class="row">
<div class="col-xl-6">
<p>
Click header title to sort column:
<img src="/img/sort.png?[% timestamp %]" alt="Screenshot: Sort colums" class="img-fluid rounded">
</p>
</div>
<div class="col-xl-6">
<p>
Click group header title icon to show more colums:
<img src="/img/show-more.png?[% timestamp %]" alt="Screenshot: Show more colums" class="img-fluid rounded">
</p>
</div>
</div>
<h3>Keyboard shortcuts</h3>
<p>You can navigate the <a href="/grid.html">Instance Picker</a> with your keyboard.</p>
<p>
Press <kbd>Ctrl</kbd> + <kbd>/</kbd> to focus the vCPU filter.</p>
<p>
Use the arrow keys (<kbd>←</kbd> <kbd>↑</kbd> <kbd>→</kbd> <kbd>↓</kbd>) to move focus up, down, left and right.
<kbd>Tab</kbd> will move the focus horizontally until the last cell and then move on to the next row.
<kbd>Shift</kbd> + <kbd>Tab</kbd> will move the focus horizontal backward until the first cell and then move back to the previous row.
</p>
<p>Pressing the <kbd>Space</kbd> key on a cell will select the cells row, or deselect the row if already selected.</p>
<p>With the following keyboard shortcuts you can copy selected row from the table in CSV format to your clipboard:</p>
<ul>
<li><kbd>Ctrl</kbd> + <kbd>c</kbd> : Copy selected rows with shown column</li>
<li><kbd>Ctrl</kbd> + <kbd>x</kbd> : Copy selected rows with all column</li>
</ul>
<p>The grid header also supports full keyboard navigation:</p>
<ul>
<li>Press <kbd>Enter</kbd> to toggle the sorting state of that column.</li>
<li>Press <kbd>Ctrl</kbd> + <kbd>Enter</kbd> to open the menu for the focused header.</li>
<li>When a menu is open, simply press <kbd>Esc</kbd> to close it and the focus will return to the header.</li>
</ul>
<h2>Resources of the Information</h2>
<p>The information was obtained from the following different Google websites:</p>
<div class="row">
<div class="col-xl-6">
<ul>
<li>
<a href="https://cloud.google.com/compute/docs/machine-types#machine_type_comparison" rel="nofollow">Machine series comparison</a>
<ul>
<li>
<a href="https://cloud.google.com/compute/docs/accelerator-optimized-machines#a2-vms" rel="nofollow">A2</a>,
<a href="https://cloud.google.com/compute/docs/accelerator-optimized-machines#a3-vms" rel="nofollow">A3</a> and
<a href="https://cloud.google.com/compute/docs/accelerator-optimized-machines#g2-vms" rel="nofollow">G2</a> accelerator optimized machines
</li>
<li>
<a href="https://cloud.google.com/compute/docs/storage-optimized-machines#z3_series" rel="nofollow">Z3</a> storage optimized machines
</li>
<li>
<a href="https://cloud.google.com/compute/docs/compute-optimized-machines#c2_machine_types" rel="nofollow">C2</a>,
<a href="https://cloud.google.com/compute/docs/compute-optimized-machines#c2d_machine_types" rel="nofollow">C2D</a> and
<a href="https://cloud.google.com/compute/docs/compute-optimized-machines#h3_series" rel="nofollow">H3</a> compute optimized machine series
</li>
<li>
<a href="https://cloud.google.com/compute/docs/memory-optimized-machines#m1_machine_types" rel="nofollow">M1</a>,
<a href="https://cloud.google.com/compute/docs/memory-optimized-machines#m2_machine_types" rel="nofollow">M2</a>,
<a href="https://cloud.google.com/compute/docs/memory-optimized-machines#m3_machine_types" rel="nofollow">M3</a> and
<a href="https://cloud.google.com/compute/docs/memory-optimized-machines#m4_machine_types" rel="nofollow">M4</a> memory optimized machine series
</li>
<li>
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#c3_series" rel="nofollow">C3</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#c3d_series" rel="nofollow">C3D</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#c4_series" rel="nofollow">C4</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#c4a_series" rel="nofollow">C4A</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#c4d_series" rel="nofollow">C4D</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#e2_machine_types" rel="nofollow">E2</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#n1_machines" rel="nofollow">N1</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#n2_series" rel="nofollow">N2</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#n2d_machines" rel="nofollow">N2D</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#n4_series" rel="nofollow">N4</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#n4a_series" rel="nofollow">N4A</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#n4d_series" rel="nofollow">N4D</a>,
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#t2d_machines" rel="nofollow">T2D</a> and
<a href="https://cloud.google.com/compute/docs/general-purpose-machines#t2a_machines" rel="nofollow">T2A</a> general purpose machine series
</li>
</ul>
</li>
</ul>
</div>
<div class="col-xl-6">
<ul>
<li><a href="https://cloud.google.com/compute/docs/regions-zones#available" rel="nofollow">Available regions and zones</a></li>
<li><a href="https://cloud.google.com/compute/docs/cpu-platforms" rel="nofollow">CPU Platform</a></li>
<li><a href="https://cloud.google.com/compute/docs/benchmarks-linux" rel="nofollow">Benchmarks for Linux VM instances</a></li>
<li><a href="https://cloud.google.com/solutions/sap/docs/certifications-sap-apps#sap-certified-vms" rel="nofollow">Certified SAP applications on Google Cloud</a></li>
<li><a href="https://cloud.google.com/solutions/sap/docs/certifications-sap-hana#hana-cert-table-vms" rel="nofollow">Certified machine types for SAP HANA</a></li>
</ul>
</div> <!-- // col -->
</div> <!-- // row -->
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/instance.tt2
================================================
[%- PROCESS header.tt2 -%]
<h1>Google Compute Engine Machine Type [% instance.name %]</h1>
<blockquote class="blockquote">
<p>
[% IF instance.family %][% instance.family %][% END %]
Google Compute Engine machine type [% instance.name %] with [% instance.vCpus%] vCPU and [% instance.memoryGB %] GB memory.
[% IF instance.localSsd > 1 %]Bundled with [% instance.localSsd FILTER format("%.0f") %] GB local SSD.[% END %]
[% IF instance.name.search('-lssd') %]Local SSD storage is required and automatically attached. Additional costs for Local SSD storage are charged.[% END %]
[%- IF instance.sap || instance.hana -%]
GCE machine type [% instance.name %] is certified for
[% IF instance.sap %]SAP applications[% END %]
[% IF instance.sap && instance.hana%]and[% END %]
[% IF instance.hana %]SAP HANA[% END %]
on Google Cloud Platform.
[%- END -%]
Available in [% regions.size %] Google Cloud region[% IF regions.size > 1 %]s[% END %].
[% notAllCpuPlatformsAvailable = 0; FOREACH region IN regions; IF region.availableCpuPlatformCount < instance.cpuPlatformCount; notAllCpuPlatformsAvailable = 1; END; END; %]
[% IF notAllCpuPlatformsAvailable %]<mark>Not all CPU platforms are available in all regions.</mark>[% END %]
</p>
</blockquote>
<p class="d-grid gap-2 d-lg-block">
<a class="btn btn-success" href="/grid.html?name=[% instance.name %]" role="button">✅ Instance Picker with filter on machine type [% instance.name %]</a>
<a class="btn btn-warning" href="/comparison/[% instance.name %]/vs.html" role="button">Compare machine type [% instance.name %]</a>
</p>
<div class="row">
<div class="col-xxl-6">
<h2>Google Cloud VM [% instance.name %]</h2>
<p>Technical facts about the Google Compute Engine machine type [% instance.name %].</p>
<div class="table-responsive">
<table class="table table-hover table-striped table-bordered">
<tr>
<th>Series</th>
<td>[% instance.series %]</td>
</tr>
<tr>
<th>Family</th>
<td>[% instance.family %]</td>
</tr>
<tr>
<th>vCPU</th>
<td>[% instance.vCpus %][% badgeSharedCpu(instance) %]</td>
</tr>
<tr>
<th>Memory</th>
<td>[% instance.memoryGB %] GB</td>
</tr>
<tr>
<th>CPU Manufactur</th>
<td>[% badgeCpuManufactur(instance) %]</td>
</tr>
<tr>
<th>CPU Platform</th>
<td>[% listCpuPlatform(instance) %]</td>
</tr>
<tr>
<th>CPU Base Frequency</th>
<td>[% IF instance.cpuBaseClock > 0 %][% instance.cpuBaseClock %] GHz[% ELSE %]<span class="text-muted">?</span>[% END %]</td>
</tr>
<tr>
<th>CPU Turbo Frequency</th>
<td>[% IF instance.cpuTurboClock > 0 %][% instance.cpuTurboClock %] GHz[% ELSE %]<span class="text-muted">?</span>[% END %]</td>
</tr>
<tr>
<th>CPU Max. Turbo Frequency</th>
<td>[% IF instance.cpuSingleMaxTurboClock > 0 %][% instance.cpuSingleMaxTurboClock %] GHz[% ELSE %]<span class="text-muted">?</span>[% END %]</td>
</tr>
[% IF instance.acceleratorCount %]
<tr>
<th>Accelerator (GPUs)</th>
<td>[% instance.acceleratorCount %]</td>
</tr>
<tr>
<th>Accelerator Type</th>
<td>[% instance.acceleratorType %]</td>
</tr>
[% END %]
<tr>
<th>EEMBC CoreMark Benchmark (<a href="https://www.eembc.org/coremark">?</a>)</th>
<td>[% IF instance.coremarkScore %][% instance.coremarkScore %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>EEMBC CoreMark Standard Deviation</th>
<td>[% IF instance.standardDeviation %][% instance.standardDeviation %] %[% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>EEMBC CoreMark Sample Count</th>
<td>[% IF instance.sampleCount %][% instance.sampleCount %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>SAP Standard Benchmark (<a href="https://www.sap.com/about/benchmark.html">?</a>)</th>
<td>[% IF instance.saps %][% instance.saps %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>Network Bandwidth</th>
<td>[% instance.bandwidth %] Gbps</td>
</tr>
<tr>
<th>Network Tier 1</th>
<td>[% IF instance.tier1 %][% instance.tier1 %] Gbps[% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th title="Disk usage is charged separately from machine type pricing!">Max. Disk Size</th>
<td>[% instance.diskSizeTiB %] TB</td>
</tr>
<tr>
<th title="Disk usage is charged separately from machine type pricing!">Max. Number of Disks</th>
<td>[% instance.disks %]</td>
</tr>
<tr>
<th>Local SSD</th>
<td>
[% booleanLocalSsd(instance) %]
[% bundledLocalSsd(instance) %]
</td>
</tr>
<tr>
<th>SAP Application</th>
<td>[% booleanSap(instance) %]</td>
</tr>
<tr>
<th>SAP HANA</th>
<td>[% booleanHana(instance) %]</td>
</tr>
<tr>
<th>Spot Provisioning Mode (Spot VM)</th>
<td>[% booleanSpot(instance) %]</td>
</tr>
<tr>
<th>Sustained Use Discount (SUD)</th>
<td>[% booleanSud(instance) %]</td>
</tr>
<tr>
<th title="Google Compute Engine API Description">GCE API Description</th>
<td>[% instance.description %]</td>
</tr>
</table>
</div><!-- table-responsive -->
</div> <!-- // col -->
<div class="col-xxl-6">
<h2>Costs (Pricing) for [% instance.name %]</h2>
<p>Cost and pricing across all regions for Google Cloud VM [% instance.name %].</p>
<h3>Price per Hour</h3>
<div class="table-responsive">
<table class="table table-hover table-striped table-bordered">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" title="Lowest price across all regions">Min.</th>
<th scope="col" title="Average price across all regions">Avg.</th>
<th scope="col" title="Highest price across all regions">Max.</th>
</tr>
</thead>
<tbody>
<tr>
<th>Standard price per hour</th>
<td class="currency">[% instance.minHour %]</td>
<td class="currency">[% instance.avgHour %]</td>
<td class="currency">[% instance.maxHour %]</td>
</tr>
[% IF instance.spot && instance.avgHourSpot > 0 %]
<tr>
<th>Spot provisioning model (Spot VM)</th>
<td class="currency">[% instance.minHourSpot %]</td>
<td class="currency">[% instance.avgHourSpot %]</td>
<td class="currency">[% instance.maxHourSpot %]</td>
</tr>
[% END %]
</tbody>
</table>
</div>
<h3>Price per Month</h3>
<div class="table-responsive">
<table class="table table-hover table-striped table-bordered">
<thead>
<tr>
<th scope="col"></th>
<th scope="col" title="Lowest price across all regions">Min.</th>
<th scope="col" title="Average price across all regions">Avg.</th>
<th scope="col" title="Highest price across all regions">Max.</th>
</tr>
</thead>
<tbody>
<tr>
<th>Price per month[% IF instance.sud %] with sustained use discount (SUD)[% END %]</th>
<td class="currency">[% instance.minMonth %]</td>
<td class="currency">[% instance.avgMonth %]</td>
<td class="currency">[% instance.maxMonth %]</td>
</tr>
[% IF instance.spot && instance.avgMonthSpot > 0 %]
<tr>
<th>Spot provisioning model (Spot VM)</th>
<td class="currency">[% instance.minMonthSpot %]</td>
<td class="currency">[% instance.avgMonthSpot %]</td>
<td class="currency">[% instance.maxMonthSpot %]</td>
</tr>
[% END %]
<tr>
<th>1 year commitment (CUD)</th>
<td class="currency">[% instance.minMonth1yCud %]</td>
<td class="currency">[% instance.avgMonth1yCud %]</td>
<td class="currency">[% instance.maxMonth1yCud %]</td>
</tr>
<tr>
<th>3 year commitment (CUD)</th>
<td class="currency">[% instance.minMonth3yCud %]</td>
<td class="currency">[% instance.avgMonth3yCud %]</td>
<td class="currency">[% instance.maxMonth3yCud %]</td>
</tr>
</tbody>
</table>
</div><!-- table-responsive -->
<h3>Operating System Licenses Costs</h3>
<p>Monthly costs for paid <i>premium</i> operating system licenses for Google Compute Engine machine type [% instance.name %].</p>
<div class="table-responsive">
<table class="table table-sm table-hover table-striped table-bordered">
<thead>
<tr>
<th scope="col">Operating System</th>
<th scope="col">Month</th>
<th scope="col">1Y CUD</th>
<th scope="col">3Y CUD</th>
</tr>
</thead>
<tbody>
<tr>
<th>Microsoft Windows Server</th>
<td class="currency">[% instance.monthWindows %]</td>
<td></td>
<td></td>
</tr>
<tr>
<th>SUSE Linux Enterprise Server</th>
<td class="currency">[% instance.monthSles %]</td>
<td></td>
<td></td>
</tr>
<tr>
<th>Red Hat Enterprise Linux</th>
<td class="currency">[% instance.monthRhel %]</td>
<td class="currency">[% instance.monthRhel1yCud %]</td>
<td class="currency">[% instance.monthRhel3yCud %]</td>
</tr>
<tr>
<th>SUSE Linux Enterprise Server for SAP</th>
<td class="currency">[% instance.monthSlesSap %]</td>
<td class="currency">[% instance.monthSlesSap1yCud %]</td>
<td class="currency">[% instance.monthSlesSap3yCud %]</td>
</tr>
<tr>
<th>Red Hat Enterprise Linux for SAP</th>
<td class="currency">[% instance.monthRhelSap %]</td>
<td class="currency">[% instance.monthRhelSap1yCud %]</td>
<td class="currency">[% instance.monthRhelSap3yCud %]</td>
</tr>
</table>
</div><!-- table-responsive -->
</div> <!-- // col -->
</div> <!-- // row -->
<h2>Price per Region</h2>
[%
cost_hour_difference = instance.maxHour - instance.minHour;
cost_hour_difference_percent = cost_hour_difference*100 / instance.maxHour
%]
<p>
Costs and pricing for Google Compute Engine machine type [% instance.name %] in Google Cloud regions in which the VM is available.
Between the most expensive and the cheapest region is a price <mark>difference of [% cost_hour_difference_percent FILTER format("%.0f") %]%</mark>.
</p>
<div class="table-responsive">
<table
class="table table-sm table-hover table-striped table-bordered"
data-classes="table table-sm table-hover table-striped table-bordered"
data-toggle="table"
data-sort-name="hour"
data-sort-order="asc"
data-sortable="true"
data-sticky-header="true"
>
<thead>
<tr>
<th scope="col" data-sortable="true">Region</th>
<th scope="col" data-sortable="true">Location</th>
<th scope="col" data-sortable="true">#Zones</th>
<th scope="col" data-sortable="true" title="CPU Platforms" >#Platf.</th>
<!-- Costs -->
<th scope="col" data-field="hour" data-sortable="true">Hour</th>
[% IF instance.spot && instance.avgHourSpot > 0 %]<th scope="col" data-sortable="true">Spot</th>[% END %]
<th scope="col" data-sortable="true">Month</th>
<th scope="col" data-sortable="true">1Y CUD</th>
<th scope="col" data-sortable="true">3Y CUD</th>
</tr>
</thead>
<tbody>
[% FOREACH region IN regions %]
<tr>
<td>
<a
href="/[% region.name %]/[% instance.name %].html"
title="Google Compute Engine machine type [% instance.name %] in Google Cloud region [% region.name %]">
[% region.name %]
</a>
</td>
<td>
[% IF region.regionLocation %][% region.regionLocation %][% ELSE %]<span class="text-muted">?</span>[% END %]
[% iconLowCo2Region(region) %]
</td>
<td [% IF region.zoneCount < 1%]class="table-danger"[% END%] title="Available [% region.zoneCount %] zone[% IF region.zoneCount > 1 %]s[% END %] in region [% region.name %]">[% IF region.zoneCount %][% region.zoneCount %][% ELSE %]<span class="text-muted">?</span>[% END %]</td>
<td [% IF region.availableCpuPlatformCount < instance.cpuPlatformCount %]class="table-warning"[% END%] title="Available CPU platforms in region [% region.name %]">[% IF region.availableCpuPlatformCount %][% region.availableCpuPlatformCount %][% ELSE %]<span class="text-muted">?</span>[% END %]</td>
<!-- Costs -->
<td
class="currency [% IF region.hour >= instance.maxHour %]table-danger[% ELSIF region.hour > instance.avgHour %]table-warning[% ELSE %]table-success[% END %]"
title="Costs per hour for machine type [% instance.name %] in region [% region.name %]: [% region.hour %] USD">[% region.hour %]</td>
[% IF instance.spot && instance.avgHourSpot > 0 %]
<td
class="currency [% IF region.hourSpot >= instance.maxHourSpot %]table-danger[% ELSIF region.hourSpot > instance.avgHourSpot %]table-warning[% ELSE %]table-success[% END %]"
title="Costs per hour for machine type [% instance.name %] in region [% region.name %] with spot provisioning model (Spot VM): [% region.hourSpot %] USD">[% region.hourSpot %]</td>
[% END %]
<td
class="currency [% IF region.month >= instance.maxMonth %]table-danger[% ELSIF region.month > instance.avgMonth %]table-warning[% ELSE %]table-success[% END %]"
title="Costs per month for machine type [% instance.name %] in region [% region.name %]: [% region.month %] USD[% IF instance.sud %] with sustained use discounts (SUD) applied[% END %]">[% region.month %]</td>
<td
class="currency [% IF region.month1yCud >= instance.maxMonth1yCud %]table-danger[% ELSIF region.month1yCud > instance.avgMonth1yCud %]table-warning[% ELSE %]table-success[% END %]"
title="Costs per month for machine type [% instance.name %] in region [% region.name %] with 1 year commitment (CUD): [% region.month1yCud %] USD">[% region.month1yCud %]</td>
<td
class="currency [% IF region.month3yCud >= instance.maxMonth3yCud %]table-danger[% ELSIF region.month3yCud > instance.avgMonth3yCud %]table-warning[% ELSE %]table-success[% END %]"
title="Costs per month for machine type [% instance.name %] in region [% region.name %] with 3 year commitment (CUD): [% region.month3yCud %] USD">[% region.month3yCud %]</td>
</tr>
[% END %]
</tbody>
</table>
</div><!-- table-responsive -->
[% PROCESS footer.tt2 %]
================================================
FILE: build/src/instance_in_region.json
================================================
[% json %]
================================================
FILE: build/src/instance_in_region.tt2
================================================
[%- PROCESS header.tt2 -%]
<h1>
Google Compute Engine Machine Type [% instance.name %]
in Region [% instance.region %]
[% IF instance.regionLocation %] <small class="text-muted">[% instance.regionLocation %]</small>[% END %]
<small>[% badgeLowCo2Region(instance) %]</small>
</h1>
<blockquote class="blockquote">
<p>
[% IF instance.family %][% instance.family %][% END %]
Google Compute Engine machine type <a href="/[% instance.name %].html" title="Show machine type [% instance.name %] in all regions">[% instance.name %]</a>
with [% instance.vCpus%] vCPU and [% instance.memoryGB %] GB memory
in Google Cloud region <a href="/[% instance.region %].html" title="Show all machine types in region [% instance.region %]">[% instance.region %]</a>
[% IF instance.regionLocationLong %]([% instance.regionLocationLong %])[% ELSIF instance.regionLocation %]([% instance.regionLocation %])[% END %].
[% IF instance.localSsd > 1 %]Bundled with [% instance.localSsd FILTER format("%.0f") %] GB local SSD.[% END %]
[% IF instance.name.search('-lssd') %]Local SSD storage is required and automatically attached. Additional costs for Local SSD storage are charged.[% END %]
[%- IF instance.sap || instance.hana -%]
GCE machine type [% instance.name %] is certified for
[% IF instance.sap %]SAP applications[% END %]
[% IF instance.sap && instance.hana%]and[% END %]
[% IF instance.hana %]SAP HANA[% END %]
on Google Cloud Platform.
[%- END -%]
Available in [% instance.zoneCount %] zone[% IF instance.zoneCount > 1 %]s[% END %].
[% IF instance.availableCpuPlatformCount < instance.cpuPlatformCount %]<mark>Not all CPU platforms are available in region [% instance.region %][% IF instance.regionLocation %] ([% instance.regionLocation %])[% END %].</mark>[% END %]
[% notAllCpuPlatformsAvailableInZones = 0; FOREACH cpuPlatform IN instance.availableCpuPlatform.split(',').sort; cpu = cpuPlatform.remove('\s'); %]
<!-- cpu: '[% cpu %]' -->
[% FOREACH zone IN instance.zones.split(', ').sort; %]
<!-- zone: '[% zone %]' -->
[% FOREACH z IN zones; IF z.name == zone; %]
[% available = z.availableCpuPlatforms.remove('\s') %]
[% IF available.search(cpu); notAllCpuPlatformsAvailableInZones = notAllCpuPlatformsAvailableInZones; ELSE; notAllCpuPlatformsAvailableInZones = notAllCpuPlatformsAvailableInZones + 1; END; %]
<!-- z.name: '[% z.name %]' -->
<!-- available: '[% available %]' -->
<!-- notAllCpuPlatformsAvailableInZones: [% notAllCpuPlatformsAvailableInZones %] -->
[% END; END; %]
[% END %]
[%END %]
[% IF notAllCpuPlatformsAvailableInZones %]<mark>Not all CPU platforms are available in all zones in region [% instance.region %][% IF instance.regionLocation %] ([% instance.regionLocation %])[% END %].</mark>[% END %]
</p>
</blockquote>
<p class="d-grid gap-2 d-lg-block">
<a class="btn btn-success" href="/grid.html?region=[% instance.region %]&name=[% instance.name %]" role="button">✅ Instance Picker [% instance.name %] in [% instance.region %]</a>
<a class="btn btn-primary" href="/[% instance.name %].html" role="button" title="Show machine type [% instance.name %] in all regions">Show [% instance.name %]</a>
<a class="btn btn-primary" href="/[% instance.region %].html" role="button" title="Show all machine types in region [% instance.region %]">Show [% instance.region %]</a>
<a class="btn btn-warning" href="/comparison/[% instance.name %]/vs.html" role="button">Compare [% instance.name %]</a>
</p>
<div class="row">
<div class="col-xxl-6">
<h2>Google Cloud VM [% instance.name %]</h2>
<p>Technical facts about the Google Compute Engine machine type [% instance.name %] in Google Cloud Region [% instance.region %][% IF instance.regionLocation %] ([% instance.regionLocation %])[% END %].</p>
<div class="table-responsive">
<table class="table table-hover table-striped table-bordered">
<tr>
<th>Series</th>
<td>[% instance.series %]</td>
</tr>
<tr>
<th>Family</th>
<td>[% instance.family %]</td>
</tr>
<tr>
<th>vCPU</th>
<td>[% instance.vCpus %][% badgeSharedCpu(instance) %]</td>
</tr>
<tr>
<th>Memory</th>
<td>[% instance.memoryGB %] GB</td>
</tr>
<tr>
<th>CPU Manufactur</th>
<td>[% badgeCpuManufactur(instance) %]</td>
</tr>
<tr>
<th>CPU Platform</th>
<td>
<ul class="list-unstyled">
<!--
cpuPlatformCount: [% instance.cpuPlatformCount %]
cpuPlatform: [% instance.cpuPlatform %]
availableCpuPlatformCount: [% instance.availableCpuPlatformCount %]
availableCpuPlatform: [% instance.availableCpuPlatform %]
-->
[% FOREACH cpuPlatform IN instance.cpuPlatform.split(',').sort; cpu = cpuPlatform.remove('\s'); available = instance.availableCpuPlatform.remove('\s'); %]
<!-- cpu: '[% cpu %]' -->
<!-- available: '[% available %]' -->
[% IF available.search(cpu) %]
<li title="[% cpuPlatform %] is available in region [% instance.region %]">✔️ [% cpuPlatform %]</li>
[% ELSE %]
<li class="text-muted" title="[% cpuPlatform %] is not available in region [% instance.region %]">❌ [% cpuPlatform %]</li>
[% END %]
[% END %]
</ul>
</td>
</tr>
<tr>
<th>CPU Base Frequency</th>
<td>[% IF instance.cpuBaseClock > 0 %][% instance.cpuBaseClock %] GHz[% ELSE %]<span class="text-muted">?</span>[% END %]</td>
</tr>
<tr>
<th>CPU Turbo Frequency</th>
<td>[% IF instance.cpuTurboClock > 0 %][% instance.cpuTurboClock %] GHz[% ELSE %]<span class="text-muted">?</span>[% END %]</td>
</tr>
<tr>
<th>CPU Max. Turbo Frequency</th>
<td>[% IF instance.cpuSingleMaxTurboClock > 0 %][% instance.cpuSingleMaxTurboClock %] GHz[% ELSE %]<span class="text-muted">?</span>[% END %]</td>
</tr>
[% IF instance.acceleratorCount %]
<tr>
<th>Accelerator (GPUs)</th>
<td>[% instance.acceleratorCount %]</td>
</tr>
<tr>
<th>Accelerator Type</th>
<td>[% instance.acceleratorType %]</td>
</tr>
[% END %]
<tr>
<th>EEMBC CoreMark Benchmark (<a href="https://www.eembc.org/coremark">?</a>)</th>
<td>[% IF instance.coremarkScore %][% instance.coremarkScore %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>EEMBC CoreMark Standard Deviation</th>
<td>[% IF instance.standardDeviation %][% instance.standardDeviation %] %[% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>EEMBC CoreMark Sample Count</th>
<td>[% IF instance.sampleCount %][% instance.sampleCount %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>SAP Standard Benchmark (<a href="https://www.sap.com/about/benchmark.html">?</a>)</th>
<td>[% IF instance.saps %][% instance.saps %][% ELSE %]<span class="text-muted">-</span>[% END %]</td>
</tr>
<tr>
<th>Network Bandwidth</th>
<td>[% instance.b
gitextract_uvs6_j8g/
├── .github/
│ ├── FUNDING.yml
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── config.yml
│ │ └── feature_request.md
│ └── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── build/
│ ├── 00_config.sh
│ ├── 01_create_database.sh
│ ├── 01_create_database.sql
│ ├── 02_get.sh
│ ├── 03_copy.pl
│ ├── 04_clean_up.sh
│ ├── 05_copy_disks.pl
│ ├── 05_copy_instances.pl
│ ├── 06_add_costs.pl
│ ├── 07_add.sh
│ ├── 08_cpu.pl
│ ├── 08_publicipranges.pl
│ ├── 08_publicipranges.sh
│ ├── 09_more.sh
│ ├── 10_export.sh
│ ├── 11_test.sh
│ ├── README.md
│ ├── app.psgi
│ ├── build.sh
│ ├── cpanfile
│ ├── site.pl
│ └── src/
│ ├── 404.tt2
│ ├── ads.txt
│ ├── amd.tt2
│ ├── arm.tt2
│ ├── comparison.tt2
│ ├── config.tt2
│ ├── disk.tt2
│ ├── diskpricing.tt2
│ ├── disks.js
│ ├── disks.tt2
│ ├── download.tt2
│ ├── favicon.tt2
│ ├── footer.tt2
│ ├── gcosts.tt2
│ ├── gpu.tt2
│ ├── grid.tt2
│ ├── hana.tt2
│ ├── header.tt2
│ ├── images.tt2
│ ├── img/
│ │ └── favicon/
│ │ ├── README.txt
│ │ └── site.webmanifest
│ ├── imprint.tt2
│ ├── index.tt2
│ ├── instance.tt2
│ ├── instance_in_region.json
│ ├── instance_in_region.tt2
│ ├── instances.tt2
│ ├── instances_header.tt2
│ ├── instances_tr.tt2
│ ├── intel.tt2
│ ├── macros.tt2
│ ├── main.js
│ ├── map.tt2
│ ├── meta.tt2
│ ├── platforms.tt2
│ ├── popin-min.js
│ ├── region.tt2
│ ├── regions.tt2
│ ├── regions_header.tt2
│ ├── robots.txt
│ ├── sap.tt2
│ ├── sitemap.tt2
│ └── vs.tt2
├── instances/
│ ├── README.md
│ ├── clean_up.sql
│ └── series/
│ ├── a2.sql
│ ├── a3.sql
│ ├── c2.sql
│ ├── c2d.sql
│ ├── c3.sql
│ ├── c3d.sql
│ ├── c4.sql
│ ├── c4a.sql
│ ├── c4d.sql
│ ├── cpu/
│ │ ├── README.md
│ │ ├── coremark.csv
│ │ ├── coremark.ods
│ │ ├── coremark.pl
│ │ ├── coremark.sql
│ │ └── frequency.sql
│ ├── e2.sql
│ ├── g2.sql
│ ├── gpu/
│ │ └── gpu_names.sql
│ ├── h3.sql
│ ├── m1.sql
│ ├── m2.sql
│ ├── m3.sql
│ ├── m4.sql
│ ├── n1.sql
│ ├── n2.sql
│ ├── n2d.sql
│ ├── n4.sql
│ ├── n4a.sql
│ ├── n4d.sql
│ ├── sap/
│ │ ├── hana.sql
│ │ └── sap.sql
│ ├── t2a.sql
│ ├── t2d.sql
│ └── z3.sql
└── regions/
├── README.md
├── carbon.csv
├── carbon.pl
├── carbon.sql
├── country.sql
├── extra.sql
├── regions.json
├── regions.pl
└── regions.sql
SYMBOL INDEX (17 symbols across 2 files)
FILE: build/01_create_database.sql
type "machinetypes" (line 6) | CREATE TABLE "machinetypes" (
type "zones" (line 23) | CREATE TABLE "zones" (
type "instances" (line 30) | CREATE TABLE "instances" (
type "disktypes" (line 97) | CREATE TABLE "disktypes" (
type "disks" (line 107) | CREATE TABLE "disks" (
type "images" (line 120) | CREATE TABLE "images" (
type instances (line 132) | CREATE INDEX IF NOT EXISTS "instances-name-index" ON instances(name COLL...
type instances (line 133) | CREATE INDEX IF NOT EXISTS "instances-region-index" ON instances(region ...
type instances (line 134) | CREATE INDEX IF NOT EXISTS "instances-region-name-index" ON instances(re...
type instances (line 135) | CREATE INDEX IF NOT EXISTS "instances-region-hana-index" ON instances(re...
type instances (line 136) | CREATE INDEX IF NOT EXISTS "instances-region-sap-index" ON instances(reg...
type instances (line 137) | CREATE INDEX IF NOT EXISTS "instances-region-series-index" ON instances(...
type disks (line 139) | CREATE INDEX IF NOT EXISTS "disks-name-index" ON disks(name COLLATE NOCASE)
type disks (line 140) | CREATE INDEX IF NOT EXISTS "disks-region-index" ON disks(region COLLATE ...
FILE: build/src/main.js
function booleanFormatter (line 47) | function booleanFormatter(params) {
function lowCo2Formatter (line 51) | function lowCo2Formatter(params) {
function nullFormatter (line 55) | function nullFormatter(params) {
Condensed preview — 119 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (468K chars).
[
{
"path": ".github/FUNDING.yml",
"chars": 18,
"preview": "github: Cyclenerd\n"
},
{
"path": ".github/ISSUE_TEMPLATE/bug_report.md",
"chars": 852,
"preview": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: 'Bug: Good title'\nlabels: 'bug'\nassignees: ''\n\n---"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 185,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: Contact me on Mastodon\n url: https://fosstodon.org/@cyclenerd\n "
},
{
"path": ".github/ISSUE_TEMPLATE/feature_request.md",
"chars": 633,
"preview": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: 'Feature request: Good title'\nlabels: 'enhancem"
},
{
"path": ".github/PULL_REQUEST_TEMPLATE.md",
"chars": 228,
"preview": "First off, thanks for taking the time to contribute!\n\n## Please Complete the Following\n\n- [ ] I read `CONTRIBUTING.md`\n-"
},
{
"path": ".gitignore",
"chars": 240,
"preview": "/site/**\n/build/*.csv\n/build/*.gz\n/build/*.json\n/build/*.yml\n/build/*.conf\n/build/*.db\n/build/*.db-journal\n/build/machin"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5227,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 1021,
"preview": "# How to contribute\n\nFirst off, thanks for taking the time to contribute!\n\n## Submitting changes\n\nPlease send a GitHub P"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "README.md",
"chars": 2028,
"preview": "# Google Cloud Compute Comparison\n\n[\n#\n\nsource \"00_config.sh\"\n\nsqlite3 \"$DB\" <"
},
{
"path": "build/05_copy_disks.pl",
"chars": 2279,
"preview": "#!/usr/bin/env perl\n\n# Copyright 2022 Nils Knieling. All Rights Reserved.\n#\n# Licensed under the Apache License, Version"
},
{
"path": "build/05_copy_instances.pl",
"chars": 3005,
"preview": "#!/usr/bin/env perl\n\n# Copyright 2022 Nils Knieling. All Rights Reserved.\n#\n# Licensed under the Apache License, Version"
},
{
"path": "build/06_add_costs.pl",
"chars": 7719,
"preview": "#!/usr/bin/env perl\n\n# Copyright 2022-2024 Nils Knieling. All Rights Reserved.\n#\n# Licensed under the Apache License, Ve"
},
{
"path": "build/07_add.sh",
"chars": 556,
"preview": "#!/usr/bin/env bash\nset -e\n\n#\n# Add additional machine type and region informations\n#\n\nsource \"00_config.sh\"\n\nfor MY_SER"
},
{
"path": "build/08_cpu.pl",
"chars": 4959,
"preview": "#!/usr/bin/env perl\n\n# Copyright 2022 Nils Knieling. All Rights Reserved.\n#\n# Licensed under the Apache License, Version"
},
{
"path": "build/08_publicipranges.pl",
"chars": 1466,
"preview": "#!/usr/bin/env perl\n\n# Copyright 2022 Nils Knieling. All Rights Reserved.\n#\n# Licensed under the Apache License, Version"
},
{
"path": "build/08_publicipranges.sh",
"chars": 409,
"preview": "#!/usr/bin/env bash\nset -e\n\n#\n# Add number of public IP addresses for each GCP region\n#\n\nsource \"00_config.sh\"\n\necho \"Ge"
},
{
"path": "build/09_more.sh",
"chars": 516,
"preview": "#!/usr/bin/env bash\nset -e\n\n#\n# Add more machine type informations\n#\n\nsource \"00_config.sh\"\n\necho \"Frequency (GHz)\"\nsqli"
},
{
"path": "build/10_export.sh",
"chars": 479,
"preview": "#!/usr/bin/env bash\nset -e\n\n#\n# Export CSV and SQL file\n#\n\nsource \"00_config.sh\"\n\necho \"» SQL Export\"\n{\n\techo 'DROP TABL"
},
{
"path": "build/11_test.sh",
"chars": 430,
"preview": "#!/usr/bin/env bash\nset -e\n\n#\n# Test\n#\n\nsource \"00_config.sh\"\n\n# Check TODOs\nif grep 'TODO' < \"$CSV_EXPORT\"; then\n\techo "
},
{
"path": "build/README.md",
"chars": 3435,
"preview": "# Build\n\nReady to tweak and test this webapp locally?\nFollow these instructions:\n\n## Requirements\n\n* [Google Cloud CLI]("
},
{
"path": "build/app.psgi",
"chars": 143,
"preview": "#!/usr/bin/env perl\nuse strict;\nuse warnings;\nuse Plack::App::Directory;\nmy $app = Plack::App::Directory->new({\n\troot =>"
},
{
"path": "build/build.sh",
"chars": 603,
"preview": "#!/usr/bin/env bash\nset -e\n\necho \"1. Create\"\nbash \"01_create_database.sh\"\n\necho \"2. Get\"\nbash \"02_get.sh\"\n\necho \"3. Copy"
},
{
"path": "build/cpanfile",
"chars": 314,
"preview": "# Check version with 'cpan -D DBD::SQLite'\nrecommends 'perl', '5.34';\nrequires 'App::Options', '1.12';\nrequires 'Encode"
},
{
"path": "build/site.pl",
"chars": 30144,
"preview": "#!/usr/bin/env perl\n\n# Copyright 2022-2026 Nils Knieling. All Rights Reserved.\n#\n# Licensed under the Apache License, Ve"
},
{
"path": "build/src/404.tt2",
"chars": 414,
"preview": "[%- PROCESS header.tt2 -%]\n\n</div> <!-- // container-fluid -->\n<div class=\"container\">\n\n<h1>404 - Page Not Found</h1>\n\n<"
},
{
"path": "build/src/ads.txt",
"chars": 58,
"preview": "google.com, pub-7267449040388963, DIRECT, f08c47fec0942fa0"
},
{
"path": "build/src/amd.tt2",
"chars": 1142,
"preview": "[%- PROCESS header.tt2 -%]\n[%- PROCESS instances_header.tt2 -%]\n\n<h1>Google Compute Engine Machine Types with AMD CPU Pl"
},
{
"path": "build/src/arm.tt2",
"chars": 1148,
"preview": "[%- PROCESS header.tt2 -%]\n[%- PROCESS instances_header.tt2 -%]\n\n<h1>Google Compute Engine Machine Types with Arm CPU Pl"
},
{
"path": "build/src/comparison.tt2",
"chars": 23492,
"preview": "[%- PROCESS header.tt2 -%]\n\n<h1>Google Compute Engine Comparison [% instance_a.name %] vs. [% instance_b.name %]</h1>\n\n<"
},
{
"path": "build/src/config.tt2",
"chars": 1686,
"preview": "[%-\nsite = {\n\turl => 'https://gcloud-compute.com',\n\tgithub = {\n\t\trepo => 'https://github.com/Cyclenerd/google-cloud-co"
},
{
"path": "build/src/disk.tt2",
"chars": 2570,
"preview": "[%- PROCESS header.tt2 -%]\n<h1>Google Compute Engine Disk Type [% disk.name %]</h1>\n\n[%-\nminDiskSize = 10;\nIF disk.name "
},
{
"path": "build/src/diskpricing.tt2",
"chars": 5365,
"preview": "[%- PROCESS header.tt2 -%]\n[%- PROCESS regions_header.tt2 -%]\n\n<h1>Persistent Disk Pricing in Google Cloud Regions</h1>\n"
},
{
"path": "build/src/disks.js",
"chars": 2666,
"preview": "const options = {\n\tcontainer: document.getElementById('myChart'),\n\tautoSize: true,\n\ttitle: {\n\t\ttext: 'Performance by Dis"
},
{
"path": "build/src/disks.tt2",
"chars": 2755,
"preview": "[%- PROCESS header.tt2 -%]\n\n<h1>Google Compute Engine Persistent Disk Types</h1>\n\n<blockquote class=\"blockquote\">\n<p>\nGo"
},
{
"path": "build/src/download.tt2",
"chars": 2781,
"preview": "[%- PROCESS header.tt2 -%]\n\n</div> <!-- // container-fluid -->\n<div class=\"container\">\n\n<h1>Download</h1>\n\n<p>\nYou can d"
},
{
"path": "build/src/favicon.tt2",
"chars": 271,
"preview": "<link rel=\"apple-touch-icon\" sizes=\"180x180\" href=\"/apple-touch-icon.png\">\n<link rel=\"icon\" type=\"image/png\" sizes=\"32x3"
},
{
"path": "build/src/footer.tt2",
"chars": 1784,
"preview": "</div> <!-- // container -->\n</main>\n<footer class=\"footer py-3 bg-light mt-2\">\n<div class=\"container-fluid\">\n<p class=\""
},
{
"path": "build/src/gcosts.tt2",
"chars": 2583,
"preview": "[%- PROCESS header.tt2 -%]\n\n</div> <!-- // container-fluid -->\n<div class=\"container\">\n\n<h1>Google Cloud Platform Pricin"
},
{
"path": "build/src/gpu.tt2",
"chars": 3724,
"preview": "[%- PROCESS header.tt2 -%]\n[%- PROCESS instances_header.tt2 -%]\n\n<h1>Google Compute Engine Machine Types with Graphics P"
},
{
"path": "build/src/grid.tt2",
"chars": 987,
"preview": "<!doctype html>\n<html lang=\"en\">\n<head>\n<title>GCE Instance Picker</title>\n<link rel=\"canonical\" href=\"[% site.url %]/gr"
},
{
"path": "build/src/hana.tt2",
"chars": 3625,
"preview": "[%- PROCESS header.tt2 -%]\n[%- PROCESS instances_header.tt2 -%]\n\n<h1>Certified for SAP HANA on Google Cloud Platform</h1"
},
{
"path": "build/src/header.tt2",
"chars": 3923,
"preview": "<!doctype html>\n<html lang=\"en\">\n<head>\n[% PROCESS meta.tt2; %]\n[% PROCESS favicon.tt2 %]\n<link rel=\"stylesheet\" href=\"["
},
{
"path": "build/src/images.tt2",
"chars": 3397,
"preview": "[%- PROCESS header.tt2 -%]\n\n<h1>Google Compute Engine Operating System Images</h1>\n\n<blockquote class=\"blockquote\">\n<p>\n"
},
{
"path": "build/src/img/favicon/README.txt",
"chars": 378,
"preview": "This favicon was generated using the following graphics from Twitter Twemoji:\n\n- Graphics Title: 1f4b8.svg\n- Graphics Au"
},
{
"path": "build/src/img/favicon/site.webmanifest",
"chars": 263,
"preview": "{\"name\":\"\",\"short_name\":\"\",\"icons\":[{\"src\":\"/android-chrome-192x192.png\",\"sizes\":\"192x192\",\"type\":\"image/png\"},{\"src\":\"/"
},
{
"path": "build/src/imprint.tt2",
"chars": 463,
"preview": "[%- PROCESS header.tt2 -%]\n\n</div> <!-- // container-fluid -->\n<div class=\"container\">\n\n<h1>Imprint</h1>\n\n<p>🇩🇪 German l"
},
{
"path": "build/src/index.tt2",
"chars": 11508,
"preview": "[%- PROCESS header.tt2 -%]\n\n</div> <!-- // container-fluid -->\n<div class=\"container\">\n\n<h1>Google Compute Engine Machin"
},
{
"path": "build/src/instance.tt2",
"chars": 13380,
"preview": "[%- PROCESS header.tt2 -%]\n<h1>Google Compute Engine Machine Type [% instance.name %]</h1>\n\n<blockquote class=\"blockquot"
},
{
"path": "build/src/instance_in_region.json",
"chars": 10,
"preview": "[% json %]"
},
{
"path": "build/src/instance_in_region.tt2",
"chars": 18548,
"preview": "[%- PROCESS header.tt2 -%]\n<h1>\n\tGoogle Compute Engine Machine Type [% instance.name %]\n\tin Region [% instance.region %]"
},
{
"path": "build/src/instances.tt2",
"chars": 801,
"preview": "[%- PROCESS header.tt2 -%]\n[%- PROCESS instances_header.tt2 -%]\n\n<h1>Google Compute Engine Machine Types</h1>\n\n<blockquo"
},
{
"path": "build/src/instances_header.tt2",
"chars": 1368,
"preview": "<div class=\"row mt-2\">\n<div class=\"col\">\n<ul class=\"nav nav-tabs\">\n\t<li class=\"nav-item\">\n\t\t<a [% IF template.name == 'i"
},
{
"path": "build/src/instances_tr.tt2",
"chars": 6206,
"preview": "[%- MACRO instanceTh BLOCK -%]\n<tr>\n<th scope=\"col\" colspan=\"5\">Machine Type</th>\n<th scope=\"col\">Regions</th>\n<th scope"
},
{
"path": "build/src/intel.tt2",
"chars": 1176,
"preview": "[%- PROCESS header.tt2 -%]\n[%- PROCESS instances_header.tt2 -%]\n\n<h1>Google Compute Engine Machine Types with Intel CPU "
},
{
"path": "build/src/macros.tt2",
"chars": 8175,
"preview": "[%- MACRO badgeSharedCpu(instance) BLOCK -%]\n[% IF instance.sharedCpu %] <span class=\"badge bg-warning text-dark\">Shared"
},
{
"path": "build/src/main.js",
"chars": 22012,
"preview": "/*\n * Copyright 2022-2024 Nils Knieling. All Rights Reserved.\n *\n * Licensed under the Apache License, Version 2.0 (the "
},
{
"path": "build/src/map.tt2",
"chars": 1444,
"preview": "<!doctype html>\n<html lang=\"en\">\n<head>\n<title>Google Cloud Platform Region Map</title>\n<link rel=\"canonical\" href=\"[% s"
},
{
"path": "build/src/meta.tt2",
"chars": 21777,
"preview": "<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n\n[%-\n\t# title = Recommended "
},
{
"path": "build/src/platforms.tt2",
"chars": 5087,
"preview": "[%- PROCESS header.tt2 -%]\n[%- PROCESS regions_header.tt2 -%]\n\n<h1>Available CPU Platforms in Google Cloud Regions</h1>\n"
},
{
"path": "build/src/popin-min.js",
"chars": 115,
"preview": "var e=document.createElement('div');\ne.id='i59UOEcRSLY1gwtC';\ne.style.display='none';\ndocument.body.appendChild(e);"
},
{
"path": "build/src/region.tt2",
"chars": 8032,
"preview": "[%- PROCESS header.tt2 -%]\n\n<h1>\n\tGoogle Cloud Region [% region.name %]\n\t[% IF region.regionLocation %] <small class=\"te"
},
{
"path": "build/src/regions.tt2",
"chars": 5968,
"preview": "[%- PROCESS header.tt2 -%]\n[%- PROCESS regions_header.tt2 -%]\n\n<h1>Google Cloud Platform Regions</h1>\n\n[%\ntotal_public_i"
},
{
"path": "build/src/regions_header.tt2",
"chars": 687,
"preview": "<div class=\"row mt-2\">\n<div class=\"col\">\n<ul class=\"nav nav-tabs\">\n\t<li class=\"nav-item\">\n\t\t<a [% IF template.name == 'r"
},
{
"path": "build/src/robots.txt",
"chars": 356,
"preview": "User-agent: *\nDisallow: /img/\nDisallow: /index.html\nDisallow: /imprint.html\nDisallow: /grid.html\nDisallow: /map.html\nDis"
},
{
"path": "build/src/sap.tt2",
"chars": 3757,
"preview": "[%- PROCESS header.tt2 -%]\n[%- PROCESS instances_header.tt2 -%]\n\n<h1>Certified for SAP Application on Google Cloud Platf"
},
{
"path": "build/src/sitemap.tt2",
"chars": 78,
"preview": "[% site.url %]/\n[% FOREACH file IN files %][% site.url %]/[% file %]\n[% END %]"
},
{
"path": "build/src/vs.tt2",
"chars": 4210,
"preview": "[%- PROCESS header.tt2 -%]\n\n<h1>Compare Google Compute Engine Machine Type [% instance_a.name %]</h1>\n\n<blockquote class"
},
{
"path": "instances/README.md",
"chars": 4920,
"preview": "# Google Compute Engine\n\nHere you can find the SQL files that add the different information from the Google websites.\nTh"
},
{
"path": "instances/clean_up.sql",
"chars": 1205,
"preview": "/* \n * Delete not yet official 100% released machine types\n */\n\nDELETE FROM machinetypes WHERE name LIKE 'ct3-%';\nDELETE"
},
{
"path": "instances/series/a2.sql",
"chars": 999,
"preview": "/* A2 Accelerator-optimized high-gpu */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison *"
},
{
"path": "instances/series/a3.sql",
"chars": 537,
"preview": "/* A3 Accelerator-optimized machine family */\n/* https://cloud.google.com/compute/docs/accelerator-optimized-machines#a3"
},
{
"path": "instances/series/c2.sql",
"chars": 735,
"preview": "/* C2 Compute-optimized */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison */\n/* https://"
},
{
"path": "instances/series/c2d.sql",
"chars": 763,
"preview": "/* C2D Compute-optimized */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison */\n/* https:/"
},
{
"path": "instances/series/c3.sql",
"chars": 1100,
"preview": "/* C3 Compute-optimized */\n/* https://cloud.google.com/compute/docs/general-purpose-machines#c3-standard_1 */\nUPDATE ins"
},
{
"path": "instances/series/c3d.sql",
"chars": 954,
"preview": "/* C3 Compute-optimized */\n/* https://cloud.google.com/compute/docs/general-purpose-machines#c3-standard_1 */\nUPDATE ins"
},
{
"path": "instances/series/c4.sql",
"chars": 1490,
"preview": "/* C4 General-purpose */\n/* https://cloud.google.com/compute/docs/general-purpose-machines#c4_series */\nUPDATE instances"
},
{
"path": "instances/series/c4a.sql",
"chars": 1214,
"preview": "/* C4A General-purpose */\n/* https://cloud.google.com/compute/docs/general-purpose-machines#c4a_series */\nUPDATE instanc"
},
{
"path": "instances/series/c4d.sql",
"chars": 1352,
"preview": "/* C4D General-purpose */\n/* https://cloud.google.com/compute/docs/general-purpose-machines#c4d_machine_types */\nUPDATE "
},
{
"path": "instances/series/cpu/README.md",
"chars": 2564,
"preview": "# CPU Platforms\n\n* Google documentation: <https://cloud.google.com/compute/docs/cpu-platforms>\n* Wikipedia\n\t* Intel: <ht"
},
{
"path": "instances/series/cpu/coremark.csv",
"chars": 11439,
"preview": "MACHINE_TYPE;CPU;vCores;COREMARK_SCORE;STANDARD_DEVIATION;SAMPLE_COUNT\nn2-standard-2 ;Ice Lake ;2;34,735 ;0.53 ;3672\nn2-"
},
{
"path": "instances/series/cpu/coremark.pl",
"chars": 1638,
"preview": "#!/usr/bin/env perl\n\n# Copyright 2022 Nils Knieling. All Rights Reserved.\n#\n# Licensed under the Apache License, Version"
},
{
"path": "instances/series/cpu/coremark.sql",
"chars": 30341,
"preview": "/*\n * GENERATED WITH coremark.pl\n * Please see: https://github.com/Cyclenerd/google-cloud-compute-machine-types/blob/mas"
},
{
"path": "instances/series/cpu/frequency.sql",
"chars": 6437,
"preview": "/* Intel */\n/* https://cloud.google.com/compute/docs/cpu-platforms#intel_processors */\n\n/* Intel Xeon E5 (Sandy Bridge) "
},
{
"path": "instances/series/e2.sql",
"chars": 1067,
"preview": "/* E2 General-purpose */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison */\n/* https://cl"
},
{
"path": "instances/series/g2.sql",
"chars": 956,
"preview": "/* G2 Accelerator-optimized machines */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison *"
},
{
"path": "instances/series/gpu/gpu_names.sql",
"chars": 1626,
"preview": "/* \n * Replace graphics processing units (GPUs) type names\n * https://cloud.google.com/compute/docs/gpus#gpus-list\n */\n\n"
},
{
"path": "instances/series/h3.sql",
"chars": 298,
"preview": "/* H3 Compute-optimized */\n/* https://cloud.google.com/compute/docs/compute-optimized-machines#h3_series */\nUPDATE insta"
},
{
"path": "instances/series/m1.sql",
"chars": 807,
"preview": "/* M1 Memory-optimized megamem */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison */\n/* h"
},
{
"path": "instances/series/m2.sql",
"chars": 370,
"preview": "/* M2 Memory-optimized ultramem */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison */\n/* "
},
{
"path": "instances/series/m3.sql",
"chars": 438,
"preview": "/* M3 Memory-optimized */\n/* https://cloud.google.com/compute/docs/memory-optimized-machines#m3_machine_types */\nUPDATE "
},
{
"path": "instances/series/m4.sql",
"chars": 579,
"preview": "/* M3 Memory-optimized */\n/* https://cloud.google.com/compute/docs/memory-optimized-machines#m4_series */\nUPDATE instanc"
},
{
"path": "instances/series/n1.sql",
"chars": 1358,
"preview": "/* N1 General-purpose */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison */\n/* https://cl"
},
{
"path": "instances/series/n2.sql",
"chars": 1119,
"preview": "/* N2 General-purpose */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison */\n/* https://cl"
},
{
"path": "instances/series/n2d.sql",
"chars": 1189,
"preview": "/* N2D General-purpose */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison */\n/* https://c"
},
{
"path": "instances/series/n4.sql",
"chars": 807,
"preview": "/* N4 General-purpose */\n/* https://cloud.google.com/compute/docs/general-purpose-machines#n4_series */\nUPDATE instances"
},
{
"path": "instances/series/n4a.sql",
"chars": 827,
"preview": "/* N4A General-purpose */\n/* https://docs.cloud.google.com/compute/docs/general-purpose-machines?hl=en#n4a_series */\nUPD"
},
{
"path": "instances/series/n4d.sql",
"chars": 874,
"preview": "/* N4 General-purpose */\n/* https://cloud.google.com/compute/docs/general-purpose-machines#n4_series */\nUPDATE instances"
},
{
"path": "instances/series/sap/hana.sql",
"chars": 1610,
"preview": "/* SAP HANA certified machine types */\n/* https://cloud.google.com/solutions/sap/docs/certifications-sap-hana#hana-cert-"
},
{
"path": "instances/series/sap/sap.sql",
"chars": 22555,
"preview": "/* SAP certified machine types */\n/* https://cloud.google.com/solutions/sap/docs/certifications-sap-apps#sap-certified-v"
},
{
"path": "instances/series/t2a.sql",
"chars": 718,
"preview": "/* Tau T2A General-purpose */\n/* https://cloud.google.com/compute/docs/general-purpose-machines#t2a_machines */\nUPDATE i"
},
{
"path": "instances/series/t2d.sql",
"chars": 858,
"preview": "/* Tau T2D General-purpose */\n/* https://cloud.google.com/compute/docs/machine-types#machine_type_comparison */\n/* https"
},
{
"path": "instances/series/z3.sql",
"chars": 1924,
"preview": "/* Z3 Storage-optimized */\n/* https://cloud.google.com/compute/docs/storage-optimized-machines */\nUPDATE instances SET\ns"
},
{
"path": "regions/README.md",
"chars": 1380,
"preview": "# Google Cloud Regions\n\nHere you can find the SQL files that add the different information from the Google websites.\nThe"
},
{
"path": "regions/carbon.csv",
"chars": 1618,
"preview": "Google Cloud Region,Location,Google CFE,Grid carbon intensity (gCO2eq / kWh)\r\nafrica-south1,Johannesburg,0.15,656.85\r\nas"
},
{
"path": "regions/carbon.pl",
"chars": 2207,
"preview": "#!/usr/bin/env perl\n\n# Copyright 2022-2025 Nils Knieling. All Rights Reserved.\n#\n# Licensed under the Apache License, Ve"
},
{
"path": "regions/carbon.sql",
"chars": 5177,
"preview": "/*\n * GENERATED WITH carbon.pl\n * Please see: https://github.com/Cyclenerd/google-cloud-compute-machine-types/blob/maste"
},
{
"path": "regions/country.sql",
"chars": 2871,
"preview": "/* https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 */\n\nUPDATE instances SET regionLocationCountryCode = 'AU' WHERE regi"
},
{
"path": "regions/extra.sql",
"chars": 4381,
"preview": "/* Extra Data for Regions */\n\nUPDATE instances SET regionLocationLong = 'Doha, Qatar', regionLat = '25.2409741'"
},
{
"path": "regions/regions.json",
"chars": 8285,
"preview": "{\n \"africa-south1\":{\n \"name\":\"Johannesburg, South Africa\",\n \"flag\": \"https://upload.wikimedia.org/wikipedia/"
},
{
"path": "regions/regions.pl",
"chars": 1460,
"preview": "#!/usr/bin/env perl\n\n# Copyright 2022-2025 Nils Knieling. All Rights Reserved.\n#\n# Licensed under the Apache License, Ve"
},
{
"path": "regions/regions.sql",
"chars": 5748,
"preview": "/*\n * GENERATED WITH regions.pl\n * Please see: https://github.com/Cyclenerd/google-cloud-compute-machine-types/blob/mast"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the Cyclenerd/google-cloud-compute-machine-types GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 119 files (426.3 KB), approximately 128.8k tokens, and a symbol index with 17 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.