Skip to content

Commit c51440e

Browse files
dominicfallowswardpeet
authored andcommitted
feat(gatsby): configure physical cores, logical_cores or fixed number (#10257)
Gatsby 2 now utilises multi-core builds using jest-worker. By default Gatsby creates a pool of workers equal to the number of physical cores on your machine, see build-html.js. In some scenarios it may be appropriate to tell Gatsby to use a different method to calculate the number of worker pools.
1 parent 3519c43 commit c51440e

File tree

8 files changed

+109
-4
lines changed

8 files changed

+109
-4
lines changed

docs/docs/html-generation.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Finally, we call [react-dom](https://reactjs.org/docs/react-dom.html) and render
8989

9090
So, we've built the means to generate HTML for a page. This webpack bundle is saved to `public/render-page.js`. Next, we need to use it to generate HTML for all the site's pages.
9191

92-
Page HTML does not depend on other pages. So we can perform this step in parallel. We use the [jest-worker](https://github.com/facebook/jest/tree/master/packages/jest-worker) library to make this easier. The [html-renderer-queue.js](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/utils/html-renderer-queue.js) creates a pool of workers equal to the number of cores on your machine. It then partitions the pages into groups and sends them to the workers, which run [worker.js](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/utils/worker.js).
92+
Page HTML does not depend on other pages. So we can perform this step in parallel. We use the [jest-worker](https://github.com/facebook/jest/tree/master/packages/jest-worker) library to make this easier. By default, the [html-renderer-queue.js](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/utils/html-renderer-queue.js) creates a pool of workers equal to the number of physical cores on your machine. You can configure the number of pools by passing an optional environment variable, [`GATSBY_CPU_COUNT`](/docs/multi-core-builds). It then partitions the pages into groups and sends them to the workers, which run [worker.js](https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/src/utils/worker.js).
9393

9494
The workers simply iterate over each page in their partition, and call the `render-page.js` with the page. It then saves the html for the page's path in `/public`.
9595

docs/docs/multi-core-builds.md

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
title: Multi-core builds
3+
---
4+
5+
Gatsby now performs the static HTML generation phase of the overall [Page HTML Generation](/docs/html-generation/) process using multi-core parallel pools of workers. This helps speed up builds by distributing build generation tasks across multiple cores on your machine.
6+
7+
By default, Gatsby creates a pool of workers equal to the number of physical cores on your machine. See [build-html.js](/docs/html-generation/#build-htmljs).
8+
9+
In some scenarios, it may be appropriate to tell Gatsby to use a different method to calculate the number of worker pools.
10+
11+
**For example**, if you are running a Cloud server (like AWS EC2), your DevOps engineers may want to control the number of worker pools to improve the efficiency of server resource usage.
12+
13+
## Warning
14+
15+
You could negatively impact performance if you use this variable incorrectly. The default Gatsby setting (no env variable or `physical_cores`) is the safest option.
16+
17+
## Setup
18+
19+
Set the `GATSBY_CPU_COUNT` environment variable whilst running the `gatsby build` command.
20+
21+
`GATSBY_CPU_COUNT=physical_cores` - (default) calculate the number of worker pools based on the number of physical CPU cores on your machine.
22+
23+
`GATSBY_CPU_COUNT=logical_cores` - calculate the number worker of pools based on the number of logical CPU cores on your machine.
24+
25+
`GATSBY_CPU_COUNT=2` - calculate the number worker pools based on a definite number.
26+
27+
## More information
28+
29+
Understanding how processors work is complex and out of scope for this documentation.
30+
31+
In brief, some processors use _Simultaneous Multithreading (SMT)_, sometimes known as _Hyper-Threading_, which is the process of a CPU splitting each of its physical cores into virtual/logical cores.
32+
33+
SMT _can_ help to increase performance of some workloads by allowing each physical core to run two streams of work at once.
34+
35+
However, sometimes latency can be increased. As logical cores share the same physical CPU core, sometimes more memory is required for each worker in the pool and more time is needed to spawn worker processes.

packages/gatsby-plugin-manifest/src/__tests__/gatsby-node.js

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ jest.mock(`sharp`, () => {
2222
}()
2323
)
2424
sharp.simd = jest.fn()
25+
sharp.concurrency = jest.fn()
2526
return sharp
2627
})
2728
const fs = require(`fs`)

packages/gatsby-plugin-manifest/src/gatsby-node.js

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ const { defaultIcons, doesIconExist } = require(`./common.js`)
66

77
sharp.simd(true)
88

9+
// Handle Sharp's concurrency based on the Gatsby CPU count
10+
// See: http://sharp.pixelplumbing.com/en/stable/api-utility/#concurrency
11+
// See: https://www.gatsbyjs.org/docs/multi-core-builds/
12+
const cpuCoreCount = require(`gatsby/dist/utils/cpu-core-count`)
13+
sharp.concurrency(cpuCoreCount())
14+
915
function generateIcons(icons, srcIcon) {
1016
return Promise.map(icons, icon => {
1117
const size = parseInt(icon.sizes.substring(0, icon.sizes.lastIndexOf(`x`)))

packages/gatsby-plugin-sharp/src/index.js

+6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ Promise.promisifyAll(sharp.prototype, { multiArgs: true })
6262
// adventurous and see what happens with it on.
6363
sharp.simd(true)
6464

65+
// Handle Sharp's concurrency based on the Gatsby CPU count
66+
// See: http://sharp.pixelplumbing.com/en/stable/api-utility/#concurrency
67+
// See: https://www.gatsbyjs.org/docs/multi-core-builds/
68+
const cpuCoreCount = require(`gatsby/dist/utils/cpu-core-count`)
69+
sharp.concurrency(cpuCoreCount())
70+
6571
const bar = new ProgressBar(
6672
`Generating image thumbnails [:bar] :current/:total :elapsed secs :percent`,
6773
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* Calculate CPU core count
3+
* @param {boolean} [useEnvVar=false] Use the 'GATSBY_CPU_COUNT' env var to calculate the requested type of CPU cores
4+
* @returns {number} Count of the requested type of CPU cores. Defaults to number of physical cores or 1
5+
*/
6+
7+
const cpuCoreCount = (useEnvVar = false) => {
8+
try {
9+
let coreCount = require(`physical-cpu-count`) || 1
10+
11+
if (!useEnvVar) {
12+
// Return the physical CPU count,
13+
// or default to 1 if we can't detect
14+
return coreCount
15+
}
16+
17+
if (typeof process.env.GATSBY_CPU_COUNT !== `undefined`) {
18+
const coreCountArg =
19+
Number(process.env.GATSBY_CPU_COUNT) || process.env.GATSBY_CPU_COUNT
20+
21+
switch (typeof coreCountArg) {
22+
case `string`:
23+
// Leave at Default CPU count if coreCountArg === `physical_cores`
24+
25+
// CPU count === logical CPU count
26+
// throw error if we have a problem counting logical cores
27+
if (coreCountArg === `logical_cores`) {
28+
coreCount = require(`os`).cpus().length
29+
30+
if (typeof coreCount !== `number`) {
31+
throw new Error(
32+
`process.env.GATSBY_CPU_COUNT is set to 'logical_cores' but there was a problem finding the number of logical cores`
33+
)
34+
}
35+
}
36+
break
37+
38+
case `number`:
39+
// CPU count === passed in count
40+
coreCount = coreCountArg
41+
break
42+
43+
default:
44+
break
45+
}
46+
}
47+
48+
return coreCount
49+
} catch (err) {
50+
console.error(err)
51+
throw new Error(`There has been a problem counting the number of CPU cores`)
52+
}
53+
}
54+
55+
module.exports = cpuCoreCount

packages/gatsby/src/utils/html-renderer-queue.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
const Promise = require(`bluebird`)
22
const convertHrtime = require(`convert-hrtime`)
33
const Worker = require(`jest-worker`).default
4-
const numWorkers = require(`physical-cpu-count`) || 1
54
const { chunk } = require(`lodash`)
5+
const cpuCoreCount = require(`./cpu-core-count`)
66

77
const workerPool = new Worker(require.resolve(`./worker`), {
8-
numWorkers,
8+
numWorkers: cpuCoreCount(true),
99
forkOptions: {
1010
silent: false,
1111
},

www/src/data/sidebars/doc-links.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
4040
link: /docs/path-prefix/
4141
- title: How Gatsby Works with GitHub Pages
4242
link: /docs/how-gatsby-works-with-github-pages/
43-
- title: Custom Configuration
43+
- title: Multi-core builds
44+
link: /docs/multi-core-builds/
45+
- title: Custom configuration
4446
link: /docs/customization/
4547
items:
4648
- title: Babel.js

0 commit comments

Comments
 (0)