Skip to content

Commit bec682f

Browse files
committed
playwright: add playwright bench for chrome
1 parent f17645a commit bec682f

File tree

5 files changed

+230
-3
lines changed

5 files changed

+230
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/ws/ws
2+
/node_modules

README.md

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,37 @@ $ /usr/bin/time -v ./browsercore-get --dump http://127.0.0.1:1234/campfire-comme
147147
Exit status: 0
148148
```
149149

150-
## Multiple requests
150+
## Multiple requests using Playwright
151151

152-
We plan to create a benchmark to compare the memory used during multiple
153-
successive requests sent to a CDP server.
152+
We compare now multiple page loads and js evaluations using
153+
[Playwright](https://playwright.dev).
154+
155+
### Dependencies
156+
157+
To run the benchmark, you need ti install [nodejs](https://nodejs.org/en/download).
158+
159+
Once `nodejs` is installed, please run a `npm install` to install nodejs
160+
dependencies, mainly Playwright.
161+
162+
You have also to install [Google Chrome](https://www.google.com/chrome/) and
163+
Lightpanda browser, but the code is not publicly available yet.
164+
165+
### Demo web page
166+
167+
Same as previously, the benchmark assumes the demo page is running on the host.
168+
If you already have [Go](https://go.dev/dl), you can use direcly the npm script
169+
with `npm run ws`.
170+
171+
### Chrome benchmark
172+
173+
The `playwright/chrome.js` benchmark accepts multiple env vars to be configured.
174+
* `CHROME_PATH` is the path to your Google Chrome bin,
175+
* `BASE_URL` is the base url of the running web reser to request, by default `http://127.0.0.1:1234`,
176+
* `RUNS` is the number of pages loaded by the benchmark, default is `100`.
177+
178+
`npm run bench-chrome` starts a playwright process, load a Google Chrome
179+
instance and load the page to extract data 100 times.
180+
181+
```
182+
$ CHROME_PATH=`which google-chrome` npm run bench-chrome
183+
```

package-lock.json

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"type": "module",
3+
"name": "demo",
4+
"version": "1.0.0",
5+
"description": "Lightpanda browser demo",
6+
"main": "index.js",
7+
"scripts": {
8+
"install-chrome": "npx playwright install chrome",
9+
"ws": "go run ws/main.go",
10+
"bench-chrome": "node playwright/chrome.js"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "git+https://github.com/lightpanda-io/demo.git"
15+
},
16+
"keywords": [],
17+
"author": "Lightpanda",
18+
"license": "Apache 2",
19+
"bugs": {
20+
"url": "https://github.com/lightpanda-io/demo/issues"
21+
},
22+
"homepage": "https://lightpanda.io",
23+
"dependencies": {
24+
"playwright": "^1.42.1"
25+
}
26+
}

playwright/chrome.js

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Import the Chromium browser into our scraper.
2+
import { chromium } from 'playwright';
3+
4+
// options passed to the browser.
5+
let browser_options = {};
6+
7+
// chrome browser path
8+
if (process.env.CHROME_PATH) {
9+
browser_options.executablePath = process.env.CHROME_PATH;
10+
}
11+
12+
// headless
13+
if (process.env.HEADLESS) {
14+
browser_options.headless = process.env.HEADLESS === 'true';
15+
}
16+
17+
// web serveur url
18+
const baseURL = process.env.BASE_URL ? process.env.BASE_URL : 'http://127.0.0.1:1234';
19+
20+
// runs
21+
const runs = process.env.RUNS ? parseInt(process.env.RUNS) : 100;
22+
23+
// measure general time.
24+
const gstart = process.hrtime.bigint();
25+
// store all run durations
26+
let metrics = [];
27+
28+
// Open a Chromium browser. We use headless: false
29+
// to be able to watch the browser window.
30+
const browser = await chromium.launch(browser_options);
31+
32+
for (var run = 1; run<=runs; run++) {
33+
34+
// measure run time.
35+
const rstart = process.hrtime.bigint();
36+
37+
const context = await browser.newContext({
38+
baseURL: baseURL,
39+
});
40+
41+
const page = await context.newPage();
42+
await page.goto('/campfire-commerce');
43+
44+
// ensure the price is loaded.
45+
await page.waitForFunction(() => {
46+
const price = document.querySelector('#product-price');
47+
return price.textContent.length > 0;
48+
});
49+
50+
51+
// ensure the reviews are loaded.
52+
await page.waitForFunction(() => {
53+
const reviews = document.querySelectorAll('#product-reviews > div');
54+
return reviews.length > 0;
55+
});
56+
57+
let res = {};
58+
59+
res.name = await page.locator('#product-name').textContent();
60+
res.price = parseFloat((await page.locator('#product-price').textContent()).substring(1));
61+
res.description = await page.locator('#product-description').textContent();
62+
res.features = await page.locator('#product-features > li').allTextContents();
63+
res.image = await page.locator('#product-image').getAttribute('src');
64+
65+
let related = [];
66+
var i = 0;
67+
for (const row of await page.locator('#product-related > div').all()) {
68+
related[i++] = {
69+
name: await row.locator('h4').textContent(),
70+
price: parseFloat((await row.locator('p').textContent()).substring(1)),
71+
image: await row.locator('img').getAttribute('src'),
72+
};
73+
}
74+
res.related = related;
75+
76+
let reviews = [];
77+
var i =0;
78+
for (const row of await page.locator('#product-reviews > div').all()) {
79+
reviews[i++] = {
80+
title: await row.locator('h4').textContent(),
81+
text: await row.locator('p').textContent(),
82+
};
83+
}
84+
res.reviews = reviews;
85+
86+
// console.log(res);
87+
88+
process.stderr.write('.');
89+
if(run % 80 == 0) process.stderr.write('\n');
90+
91+
await page.close();
92+
await context.close();
93+
94+
metrics[run] = process.hrtime.bigint() - rstart;
95+
}
96+
97+
// Turn off the browser to clean up after ourselves.
98+
await browser.close();
99+
100+
const gduration = process.hrtime.bigint() - gstart;
101+
102+
process.stderr.write('\n');
103+
104+
const avg = metrics.reduce((s, a) => s += a) / BigInt(metrics.length);
105+
const min = metrics.reduce((s, a) => a < s ? a : s);
106+
const max = metrics.reduce((s, a) => a > s ? a : s);
107+
108+
console.log('total runs', runs);
109+
console.log('total duration (ms)', (gduration/1000000n).toString());
110+
console.log('avg run duration (ms)', (avg/1000000n).toString());
111+
console.log('min run duration (ms)', (min/1000000n).toString());
112+
console.log('max run duration (ms)', (max/1000000n).toString());
113+

0 commit comments

Comments
 (0)