Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Python scripts for measurements 2023 #1

Open
wants to merge 98 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
bf3642a
Add .py scripts to measure memory
atuchin-m May 23, 2023
0226b14
Memory measurements for windows
atuchin-m May 23, 2023
9d5f93f
browsertime support
atuchin-m May 25, 2023
61e18b1
Fix browsertime for win
atuchin-m May 25, 2023
00b14cc
Support benchmarks
atuchin-m May 25, 2023
6270588
Fix some issues
atuchin-m May 25, 2023
c354cec
more benches are supported
atuchin-m May 25, 2023
94a3318
Fix har encoding
atuchin-m May 26, 2023
90ca168
More encoding fixes just in case
atuchin-m May 26, 2023
a132077
refactor and browser lint
atuchin-m May 26, 2023
f767197
refactor and browser lint
atuchin-m May 26, 2023
a67bc6c
Merge branch 'python-scripts-for-measurements' of github.com:atuchin-…
atuchin-m May 26, 2023
498c865
add browsertime_utils.py
atuchin-m May 26, 2023
2578033
add loading_measurement.py
atuchin-m May 26, 2023
4ed61aa
Fix win memory
atuchin-m May 30, 2023
5aff8a1
Extended memory metrics
atuchin-m May 31, 2023
300abe1
Update the code, adds 2024 benchmark results
atuchin-m May 31, 2023
f448942
Fix .gitignore
atuchin-m May 28, 2024
48f7254
Fix some minor issues
atuchin-m May 30, 2024
19dd209
Fix start/stop some browsers
atuchin-m May 30, 2024
e9544ab
Fix error on unlink user_data_dir
atuchin-m May 31, 2024
4a31aaa
Fix append mode
atuchin-m May 31, 2024
f7f0c5c
write_csv on each iteration
atuchin-m May 31, 2024
978392e
Fix typing
atuchin-m May 31, 2024
7f0a19d
Change the order
atuchin-m May 31, 2024
840c226
Update memory metrics logic
atuchin-m May 31, 2024
33bc076
firefox no default options
atuchin-m May 31, 2024
73a4c26
add transfer_bytes for firefox
atuchin-m May 31, 2024
9486aeb
Update utils.js
atuchin-m Jun 3, 2024
aeffd30
Rename to script
atuchin-m Jun 3, 2024
3645f67
new memory&traffic measurement
atuchin-m Jun 3, 2024
8e19831
Add old-set.txt
atuchin-m Jun 3, 2024
c033c4d
retry-count=2 by default
atuchin-m Jun 4, 2024
5360c49
Add no-delay mode
atuchin-m Jun 4, 2024
a5aa578
Multipage support
atuchin-m Jun 5, 2024
d560b56
Add a new set
atuchin-m Jun 5, 2024
568c87d
Skip unsupported browsers
atuchin-m Jun 5, 2024
b5b39d1
Update termination logic
atuchin-m Jun 5, 2024
517ba40
Fix DDG win path
atuchin-m Jun 5, 2024
7e93c91
Update the list
atuchin-m Jun 5, 2024
cbf1575
Update win termination logic
atuchin-m Jun 5, 2024
e18ebe4
Case when there is no main process
atuchin-m Jun 5, 2024
c86ee13
edge.exe => msedge.exe
atuchin-m Jun 5, 2024
f9c0793
Fix process finding issues
atuchin-m Jun 5, 2024
600885e
Fix memory measurements
atuchin-m Jun 5, 2024
c2c5f43
Update delay and a test set
atuchin-m Jun 5, 2024
875c4be
Add open_url timeout
atuchin-m Jun 5, 2024
e599510
TranserSize for Firefox
atuchin-m Jun 5, 2024
ea78def
New logic for _Total metrics
atuchin-m Jun 5, 2024
12e5ac1
Alternative memory metrics
atuchin-m Jun 5, 2024
e6b69e3
setup startup delay
atuchin-m Jun 5, 2024
5946e5b
don't skip missed metrics
atuchin-m Jun 5, 2024
877d8b4
Replace 0 to run_time
atuchin-m Jun 5, 2024
de31ff2
Add DDG to default
atuchin-m Jun 5, 2024
15388e2
add units
atuchin-m Jun 6, 2024
ce7f36e
Add test scenario
atuchin-m Jun 6, 2024
cf783f2
Add win logging
atuchin-m Jun 6, 2024
456695f
use PrivateBytes
atuchin-m Jun 6, 2024
372b541
improme logging
atuchin-m Jun 6, 2024
fd69a25
Fix Safari
atuchin-m Jun 6, 2024
629a3c8
Support clearing Firefox cache
atuchin-m Jun 10, 2024
a38c241
Update the lists
atuchin-m Jun 10, 2024
4a14272
Remove Safari cache
atuchin-m Jun 10, 2024
989b8be
Fix Safari profile removal
atuchin-m Jun 11, 2024
4c3bf73
Fix --append
atuchin-m Jun 11, 2024
05b848a
Fix removing Safari cache
atuchin-m Jun 11, 2024
8d55dff
Fix expanding ~
atuchin-m Jun 13, 2024
2f07095
Loading 2024 results
atuchin-m Jun 14, 2024
9ee2441
update git ignore
atuchin-m Oct 14, 2024
88cf253
New list
atuchin-m Nov 6, 2024
3c42076
Fix list parsing
atuchin-m Dec 2, 2024
e3fb6a0
fix waiting before mem measurements
atuchin-m Dec 2, 2024
c189d03
Add run.py
atuchin-m Dec 4, 2024
2d1ddef
Use es modules
atuchin-m Dec 4, 2024
d84f9ca
fix execa
atuchin-m Dec 4, 2024
2c07573
Use .venv
atuchin-m Dec 4, 2024
419ad10
improve install
atuchin-m Dec 4, 2024
15edc91
Use new tab for firefox
atuchin-m Dec 4, 2024
6786b06
venv win support
atuchin-m Dec 4, 2024
78dc099
New list, reduce page delay to 10sec
atuchin-m Dec 4, 2024
5e4efde
Fix names
atuchin-m Dec 4, 2024
03956bb
update the lists
atuchin-m Dec 5, 2024
e61844e
Rework some code
atuchin-m Dec 5, 2024
ac3e642
rename the folder
atuchin-m Dec 5, 2024
6139172
update the list
atuchin-m Dec 5, 2024
fb3570d
Fix issues
atuchin-m Dec 5, 2024
ec2cc3c
Fix sp3 issue
atuchin-m Dec 5, 2024
2ae58e2
Fix some issues
atuchin-m Dec 5, 2024
872e38a
Add multipage
atuchin-m Dec 5, 2024
fb56362
Adjust delays
atuchin-m Dec 5, 2024
98cd16f
clarify the messages
atuchin-m Dec 6, 2024
b61baaa
update run.py
atuchin-m Dec 6, 2024
21f03a2
Add path to key
atuchin-m Dec 9, 2024
bd241da
Add indexes and reprocess.py
atuchin-m Dec 9, 2024
07ddd73
recalc the date
atuchin-m Dec 9, 2024
fb329ea
Randomize the order of URLs and browsers
atuchin-m Dec 12, 2024
68e43ef
add memory URLs shuffle
atuchin-m Dec 12, 2024
9f0315e
Add list v3
atuchin-m Dec 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
*.csv
*.png
.DS_Store
*.tar.gz
*.csv
results/
browser_profiles*/
browsertime/
browsertime-results/
node_modules/
__pycache__
27 changes: 27 additions & 0 deletions add_results.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env python3
# Copyright (c) 2024 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.

import argparse
from components.result_map import ResultMap
def main():
parser = argparse.ArgumentParser()
parser.add_argument('csv_file', type=str)
parser.add_argument('browser', type=str)
parser.add_argument('browser_version', type=str)
parser.add_argument('metric', type=str)
parser.add_argument('value_list', type=str)
parser.add_argument('--key', type=str)
args = parser.parse_args()

values = args.value_list.split(',')
results = ResultMap()
for v in values:
value = float(v)
results.addValue(args.browser, args.browser_version, args.metric, args.key, value)

results.write_csv(args.csv_file, True)

main()
351 changes: 351 additions & 0 deletions components/browser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,351 @@
# Copyright (c) 2023 The Brave Authors. All rights reserved.
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at https://mozilla.org/MPL/2.0/.

import os
import re
import shutil
import subprocess
import time
import logging
import platform
import psutil

from tempfile import TemporaryDirectory
from typing import Dict, List, Optional, Set, Type

from components.utils import is_mac, is_win


class Browser:
binary_name: str
use_user_data_dir: bool = True
browsertime_binary: Optional[str] = None
args: List[str] = []
extra_processes = []

temp_user_data_dir: Optional[TemporaryDirectory] = None
process: Optional[subprocess.Popen] = None

@classmethod
def name(cls) -> str:
return cls.__name__

def profile_dir(self) -> str:
raise RuntimeError('Not implemented')

def get_version(self) -> Optional[str]:
if is_win():
output = subprocess.check_output(
"wmic datafile where name=\"{:s}\" get version"
.format(self.binary()
.replace('\\','\\\\')),shell=True).decode('utf-8').rstrip()
return output.split('\n')[1]
if is_mac():
output = subprocess.check_output([self.binary(), '--version']).decode('utf-8').rstrip()
m = re.match(r'[a-zA-Z\ ]*([\d\.]+\d+)', output)
if m is None:
return None
return m.group(1)

def binary(self) -> str:
if is_mac():
return self.binary_mac()
if is_win():
return self.binary_win()
raise RuntimeError('Unsupported platform')

def binary_mac(self) -> str:
return (f'/Applications/{self.binary_name}.app/Contents/MacOS/' +
self.binary_name)

def binary_win(self) -> str:
raise RuntimeError('Not implemented')

def get_start_cmd(self, use_source_profile=False) -> List[str]:
return [self.binary()] + self.get_args(use_source_profile)

def get_args(self, use_source_profile=False) -> List[str]:
args = []
if self.use_user_data_dir:
if use_source_profile:
args.append(f'--user-data-dir={self._get_source_profile()}')
else:
args.append(f'--user-data-dir={self._get_target_profile()}')

args.extend(self.args)
return args

def _get_source_profile(self) -> str:
profile = os.path.join(os.curdir, 'browser_profiles', platform.system(),
self.name())
return os.path.abspath(profile)

def _get_target_profile(self) -> str:
if self.use_user_data_dir:
if self.temp_user_data_dir is None:
self.temp_user_data_dir = TemporaryDirectory(prefix=self.name() +
'-user-data-')
return self.temp_user_data_dir.name
assert self.profile_dir()
return self.profile_dir()

def prepare_profile(self):
if not self.use_user_data_dir:
return

target_profile = self._get_target_profile()
if os.path.exists(target_profile):
shutil.rmtree(target_profile)
if not os.path.exists(self._get_source_profile()):
raise RuntimeError('Can\'t find source profile')
shutil.copytree(self._get_source_profile(), self._get_target_profile())

def start(self, use_source_profile=False):
assert self.process is None
logging.debug(self.get_start_cmd(use_source_profile))
self.process = subprocess.Popen(self.get_start_cmd(use_source_profile),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)

def find_extra_processes(self) -> Set[psutil.Process]:
processes: Set[psutil.Process] = set()
if len(self.extra_processes) > 0:
for p in psutil.process_iter():
try:
if (any(p.name().find(e) != -1 for e in self.extra_processes) or
any(p.cmdline()[0].find(e) != -1 for e in self.extra_processes)):
processes.add(p)
except:
pass
return processes


def terminate(self, timeout = 20):
if self.process is not None:
# terminate the main process
try:
self.process.terminate()

time_spend = 0
while self.process.poll() is None and time_spend < timeout:
time.sleep(1)
time_spend += 1
except:
logging.error('Failed to terminate %s', self.name())

if self.process.poll() is None:
try:
logging.info('Killing %s pid %d', self.binary_name, self.process.pid)
if is_win():
subprocess.call(['taskkill', '/F', '/T', '/PID', str(self.process.pid)])
else:
self.process.kill()
time.sleep(2)
finally:
pass

try:
if self.temp_user_data_dir is not None:
self.temp_user_data_dir.cleanup()
except:
pass

def open_url(self, url: str):
try:
subprocess.run(self.get_start_cmd() + [url],
stdout=subprocess.PIPE,
check=self.name() != 'Opera',
timeout=15)
except:
# kill the process in case a hang
self.terminate()
raise



class _Chromium(Browser):
browsertime_binary = 'chrome'


class Brave(_Chromium):
binary_name = 'Brave Browser'

def binary_win(self) -> str:
return os.path.expandvars(
R'%ProgramFiles%\BraveSoftware\Brave-Browser\Application\brave.exe')

class BraveBeta(_Chromium):
binary_name = 'Brave Browser Beta'

def binary_win(self) -> str:
return os.path.expandvars(
R'%ProgramFiles%\BraveSoftware\Brave-Browser-Beta\Application\brave.exe')

class BraveNightly(_Chromium):
binary_name = 'Brave Browser Nightly'

def binary_win(self) -> str:
return os.path.expandvars(
R'%ProgramFiles%\BraveSoftware\Brave-Browser-Nightly\Application\brave.exe')


class DDG(Browser):
binary_name = 'DuckDuckGo'
use_user_data_dir = False
extra_processes = ['DuckDuckGo', 'com.apple.WebKit']

def terminate(self):
if is_win():
subprocess.call(['taskkill', '/IM', 'DuckDuckGo.exe'])
time.sleep(2)
super().terminate()

def binary_win(self) -> str:
return 'DuckDuckGo.exe'

def profile_dir(self) -> str:
if is_mac():
return os.path.expanduser('~/Library/Containers/com.duckduckgo.macos.browser/Data/Library/Application Support/')
raise RuntimeError('Not implemented')

def get_version(self) -> Optional[str]:
return None

def open_url(self, url: str):
if is_mac():
subprocess.check_call(['open', '-a', 'DuckDuckGo', url], stdout=subprocess.PIPE)
else:
super().open_url(url)


class Chrome(_Chromium):
binary_name = 'Google Chrome'

def binary_win(self) -> str:
return os.path.expandvars(
R'%ProgramFiles%\Google\Chrome\Application\chrome.exe')


class ChromeUBO(Chrome):
pass


class Opera(_Chromium):
binary_name = 'Opera'
args = ['--ran-launcher']
extra_processes = ['opera.exe']

def terminate(self):
if is_win():
subprocess.call(['taskkill', '/IM', 'opera.exe'])
time.sleep(2)
super().terminate()

def binary_win(self) -> str:
return os.path.expandvars(
R'%USERPROFILE%\AppData\Local\Programs\Opera\opera.exe')

class Edge(Browser):
binary_name = 'Microsoft Edge'
browsertime_binary = 'edge'
extra_processes = ['msedge.exe']

def terminate(self):
if is_win():
subprocess.call(['taskkill', '/IM', 'msedge.exe'])
time.sleep(2)
super().terminate()

def binary_win(self) -> str:
return os.path.expandvars(
R'%ProgramFiles(x86)%\Microsoft\Edge\Application\msedge.exe')


class Safari(Browser):
binary_name = 'Safari'
use_user_data_dir = False
browsertime_binary = 'safari'
extra_processes = ['Safari', 'com.apple.WebKit']

def prepare_profile(self):
assert is_mac()
dir = os.path.expanduser('~/Library/Containers/com.apple.Safari/Data/Library/Caches')
shutil.rmtree(dir, ignore_errors=True)

def profile_dir(self) -> str:
if is_mac():
return os.path.expanduser('~/Library/Safari')
raise RuntimeError('Not implemented')

def get_version(self) -> Optional[str]:
args = ['/usr/libexec/PlistBuddy',
'-c',
'print :CFBundleShortVersionString',
'/Applications/Safari.app/Contents/Info.plist']
return subprocess.check_output(args).decode('utf-8').strip()

def open_url(self, url: str):
if is_mac():
subprocess.check_call(['open', '-a', 'Safari', url], stdout=subprocess.PIPE)
else:
super().open_url(url)

class Firefox(Browser):
binary_name = 'Firefox'
use_user_data_dir = False
browsertime_binary = 'firefox'
extra_processes = ['firefox', 'Firefox', 'plugin-container']

def terminate(self):
if is_win():
subprocess.call(['taskkill', '/IM', 'firefox.exe'])
if is_mac():
subprocess.call(['killall', 'firefox'])
time.sleep(2)
super().terminate()

def prepare_profile(self):
cache_dir = None
if is_mac():
cache_dir = os.path.expanduser('~/Library/Caches/Firefox/')
if is_win():
cache_dir = os.path.expandvars(
R'%USERPROFILE%\AppData\Local\Mozilla\Firefox')
if cache_dir is not None:
shutil.rmtree(cache_dir, ignore_errors=True)

def profile_dir(self) -> str:
if is_mac():
return os.path.expanduser('~/Library/Application Support/Firefox/')
if is_win():
return os.path.expandvars(
R'%USERPROFILE%\AppData\Roaming\Mozilla\Firefox')
raise RuntimeError('Not implemented')

def binary_win(self) -> str:
return os.path.expandvars(R'%ProgramW6432%\Mozilla Firefox\firefox.exe')


SUPPORTED_BROWSER_LIST: List[Type[Browser]] = [Brave, BraveBeta, BraveNightly, Chrome, ChromeUBO, Opera, Edge, Firefox, DDG]
DEFAULT_BROWSER_LIST: List[Type[Browser]] = [Brave, Chrome, ChromeUBO, Opera, Edge, Firefox, DDG]
if is_mac():
SUPPORTED_BROWSER_LIST.append(Safari)
DEFAULT_BROWSER_LIST.append(Safari)

BROWSER_LIST_MAP: Dict[str, Type[Browser]] = {}
for b in SUPPORTED_BROWSER_LIST:
BROWSER_LIST_MAP[b.name()] = b

def get_browser_classes_from_str(name: str) -> List[Type[Browser]]:
if name == 'default':
return DEFAULT_BROWSER_LIST
result: List[type[Browser]] = []
for b in name.split(','):
cls = BROWSER_LIST_MAP.get(b)
if cls is None:
raise RuntimeError(f'No browser with name {b} found')
result.append(cls)

return result
Loading