relay_working_experiment.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. #!/usr/bin/python3
  2. #
  3. import argparse
  4. import shutil
  5. import logging
  6. import random
  7. import os
  8. import subprocess
  9. import multiprocessing
  10. import threading
  11. import time
  12. import json
  13. import gzip
  14. import pickle
  15. import tempfile
  16. import collections
  17. import gc
  18. #
  19. import stem.control
  20. import stem.descriptor.remote
  21. import stem.process
  22. #
  23. import numa
  24. import log_system_usage
  25. import chutney_manager
  26. import throughput_server
  27. import experiment_client
  28. import experiment
  29. import useful
  30. #
  31. #remote_name = 'sengler-rpi'
  32. #remote_name = 'cluck2'
  33. #remote_name = None
  34. #
  35. class CustomExperiment(experiment.Experiment):
  36. def __init__(self, use_helgrind, target_tor, target_ld_preload, num_additional_eventloops, remote_name, remote_options, *args, **kwargs):
  37. self.use_helgrind = use_helgrind
  38. self.target_tor = target_tor
  39. self.target_ld_preload = target_ld_preload
  40. self.num_additional_eventloops = num_additional_eventloops
  41. self.remote_name = remote_name
  42. self.remote_options = remote_options
  43. super().__init__(*args, **kwargs)
  44. #
  45. self.chutney_path = '/home/sengler/code/working/chutney'
  46. #self.tor_path = '/home/sengler/code/releases/tor-0.4.2.5'
  47. self.tor_path = '/home/sengler/code/dev/tor-0.4.2.6-fixed-controller'
  48. #self.tor_path = '/home/sengler/code/dev/tor-0.4.2.6-fixed-controller-kist-changes'
  49. #self.tor_path = '/home/sengler/code/working/tor'
  50. #
  51. def configure_chutney(self):
  52. #self.nodes = [chutney_manager.Node(tag='a', relay=1, authority=1, torrc='authority.tmpl') for _ in range(self.num_authorities)] + \
  53. # [chutney_manager.Node(tag='r', relay=1, torrc='relay-non-exit.tmpl') for _ in range(self.num_guards)] + \
  54. # [chutney_manager.Node(tag='e', exit=1, torrc='relay.tmpl') for _ in range(self.num_exits)] + \
  55. # [chutney_manager.Node(tag='c', client=1, torrc='client.tmpl') for _ in range(self.num_clients)]
  56. #
  57. #target_tor_path = '/home/sengler/code/working/tor/src/app/tor'
  58. #target_tor_path = '/home/sengler/code/releases/tor-0.4.2.5/src/app/tor'
  59. '''
  60. if self.remote_name == 'cluck2':
  61. local_ip = '172.19.156.16'
  62. target_ip = '172.19.156.136'
  63. #local_ip = '129.97.119.196'
  64. #target_ip = '129.97.119.226'
  65. target_hostname = 'cluck2'
  66. target_dir = '/tmp/chutney-net'
  67. #
  68. elif self.remote_name == 'cluck15':
  69. local_ip = '172.19.156.16'
  70. target_ip = '172.19.156.188'
  71. target_hostname = '129.97.119.239'
  72. target_dir = '/tmp/chutney-net'
  73. #
  74. elif self.remote_name == 'grunt3':
  75. #local_ip = '172.19.156.16'
  76. #target_ip = '172.19.156.44'
  77. #local_ip = '129.97.119.196'
  78. #target_ip = '129.97.119.203'
  79. target_hostname = '129.97.119.203'
  80. target_dir = '/tmp/chutney-net'
  81. #
  82. elif self.remote_name == 'sengler-rpi':
  83. local_ip = '129.97.119.196'
  84. target_ip = '129.97.169.9'
  85. target_hostname = target_ip
  86. target_dir = '/tmp/chutney-net'
  87. #
  88. elif self.remote_name is None:
  89. local_ip = None
  90. target_ip = None
  91. target_hostname = None
  92. target_dir = None
  93. else:
  94. raise Exception('hostname not known')
  95. #
  96. '''
  97. target_optional_args = {}
  98. if self.target_tor is not None:
  99. target_optional_args['tor'] = self.target_tor
  100. if self.use_helgrind:
  101. target_optional_args['valgrind_settings'] = ['--tool=helgrind', '-v', '--suppressions=libevent.supp', '--read-var-info=yes']
  102. if self.target_ld_preload is not None:
  103. target_optional_args['add_environ_vars'] = {'LD_PRELOAD': self.target_ld_preload}
  104. #target_optional_args['add_environ_vars'] = {'LD_PRELOAD': '/usr/lib/libprofiler.so.0'}
  105. #target_optional_args['add_environ_vars'] = {'LD_PRELOAD': '/usr/lib/libtcmalloc_and_profiler.so.4'}
  106. #target_optional_args['add_environ_vars'] = {'LD_PRELOAD': '/home/sengler/build/lib/libtcmalloc_and_profiler.so'}
  107. #target_optional_args['add_environ_vars'] = {'EVENT_NOEPOLL': '', 'EVENT_SHOW_METHOD': ''}
  108. if self.remote_options['target_ip'] is not None:
  109. target_optional_args['ip'] = self.remote_options['target_ip']
  110. if self.remote_options['target_ssh'] is not None:
  111. target_optional_args['remote_hostname'] = self.remote_options['target_ssh']
  112. if self.remote_options['target_chutney_net_dir'] is not None:
  113. target_optional_args['remote_net_dir'] = self.remote_options['target_chutney_net_dir']
  114. if self.remote_options.get('target_numa_settings', None) is not None:
  115. target_optional_args['numa_settings'] = self.remote_options['target_numa_settings']
  116. #
  117. target_optional_args['num_cpus'] = 2 # make sure it can process onion skins fast enough, and keep it consistent between computers
  118. # tor actually uses one more worker thread than what you ask for
  119. target_optional_args['num_additional_eventloops'] = self.num_additional_eventloops
  120. target_optional_args['dircache'] = False
  121. # the voting interval is 40 seconds which puts an unrealistic workload on the target, so we disable it
  122. if 'target_cpu_prof' in self.remote_options:
  123. target_cpu_prof = self.remote_options['target_cpu_prof']
  124. else:
  125. target_cpu_prof = False
  126. #
  127. target_daemon = False
  128. target_log_throughput = True
  129. target_logs = ['notice']
  130. #other_logs = ['info', 'notice']
  131. other_logs = ['notice']
  132. #if self.use_helgrind:
  133. # valgrind_settings = ['--tool=helgrind', '-v', '--suppressions=libevent.supp', '--read-var-info=yes']
  134. #else:
  135. # valgrind_settings = None
  136. #
  137. self.nodes = [chutney_manager.Node(tag='a', relay=1, authority=1, torrc='authority.tmpl', log_files=other_logs) for _ in range(self.num_authorities)] + \
  138. [chutney_manager.Node(tag='r', relay=1, torrc='relay-non-exit.tmpl', log_files=other_logs) for _ in range(self.num_guards)] + \
  139. [chutney_manager.Node(tag='target', relay=1, torrc='relay-non-exit.tmpl', log_throughput=target_log_throughput,
  140. daemon=target_daemon, log_files=target_logs, sandbox=0, google_cpu_profiler=target_cpu_prof, **target_optional_args)] + \
  141. [chutney_manager.Node(tag='e', exit=1, torrc='relay.tmpl', log_files=other_logs) for _ in range(self.num_exits)] + \
  142. [chutney_manager.Node(tag='c', client=1, torrc='client.tmpl', log_files=other_logs) for _ in range(self.num_clients)]
  143. #
  144. for node in self.nodes:
  145. if not 'num_cpus' in node.options:
  146. node.options['num_cpus'] = 2
  147. #
  148. if not 'ip' in node.options and self.remote_options['local_ip'] is not None:
  149. node.options['ip'] = self.remote_options['local_ip']
  150. #
  151. #
  152. #numa_remaining = numa.get_numa_overview()
  153. #for (node, index) in zip(self.nodes, range(len(self.nodes))):
  154. # num_cpus = node.options['num_cpus']
  155. # if num_cpus%2 != 0:
  156. # num_cpus += 1
  157. # #
  158. # if node.options['tag'] == 'target':
  159. # num_cpus = max(num_cpus, 6)
  160. # #
  161. # #if node.options['tag'] != 'target':
  162. # # (numa_node, processors) = chutney_manager.numa_scheduler(num_cpus, numa_remaining)
  163. # # node.options['numa_settings'] = (numa_node, processors)
  164. # #
  165. ##
  166. self.proxy_control_ports = [self.nodes[x].guess_control_port(x) for x in range(len(self.nodes)) if ('client', 1) in self.nodes[x].options.items()]
  167. # TODO: ^^ improve this
  168. #
  169. def start_remote_logging(self, next_action=None):
  170. if self.remote_name is None:
  171. # running locally
  172. if next_action is not None:
  173. next_action()
  174. #
  175. return
  176. #
  177. local_script_path = 'log_system_usage.py'
  178. remote_script_path = '/tmp/log_system_usage.py'
  179. remote_save_path = '/tmp/cpu-usage.pickle.gz'
  180. local_save_path = os.path.join(self.save_data_path, 'remote-cpu-usage.pickle.gz')
  181. #
  182. tor_pids = subprocess.check_output(['ssh', self.remote_name, 'pgrep tor']).decode('utf-8').split()
  183. tor_pids = [pid for pid in tor_pids]
  184. logging.info('Logging the following pids on {}: {}'.format(self.remote_name, tor_pids))
  185. command = 'python3 {} --interval 0.2 --pids {} {}'.format(remote_script_path, ','.join(tor_pids), remote_save_path)
  186. #
  187. try:
  188. subprocess.check_output(['scp', local_script_path, '{}:{}'.format(self.remote_name, remote_script_path)], stderr=subprocess.STDOUT)
  189. p = subprocess.Popen(['ssh', self.remote_name, command])
  190. #
  191. time.sleep(5)
  192. # wait a few seconds to make sure it doesn't exit immediately
  193. if p.poll() != None:
  194. raise Exception('Remote CPU monitoring script exited immediately')
  195. #
  196. if self.remote_options.get('has_sudo', False) is True:
  197. try:
  198. subprocess.check_output(['ssh', self.remote_name, 'sudo renice -n -10 -g "$(pgrep --full --exact "{}")"'.format(command)], stderr=subprocess.STDOUT)
  199. # need to set the niceness for the process group, not just the process in order to also apply to threads
  200. except:
  201. logging.warn('Could not set the nice value for the remote python script, ignoring...')
  202. #
  203. #
  204. if next_action is not None:
  205. next_action()
  206. time.sleep(5)
  207. # wait a few seconds so that we have extra data
  208. # this may be useful if we need to do averaging
  209. #
  210. if p.poll() != None:
  211. raise Exception('Remote CPU monitoring script exited before it was supposed to')
  212. #
  213. finally:
  214. try:
  215. subprocess.check_output(['ssh', self.remote_name, 'pkill --full --exact --signal sigint \'{}\''.format(command)], stderr=subprocess.STDOUT)
  216. except:
  217. logging.warn('Could not kill remote python script')
  218. #
  219. try:
  220. p.wait(timeout=30)
  221. except subprocess.TimeoutExpired:
  222. p.kill()
  223. logging.warn('Process did not end as expected, so sent a SIGKILL')
  224. except:
  225. logging.warn('Could not kill')
  226. #
  227. try:
  228. subprocess.check_output(['scp', '{}:{}'.format(self.remote_name, remote_save_path), local_save_path], stderr=subprocess.STDOUT)
  229. except:
  230. logging.warn('Failed to get remote \'{}\' data file'.format(remote_save_path))
  231. #
  232. try:
  233. subprocess.check_output(['ssh', self.remote_name, 'rm', remote_save_path], stderr=subprocess.STDOUT)
  234. except:
  235. logging.warn('Failed to delete remote \'{}\' data file'.format(remote_save_path))
  236. #
  237. try:
  238. subprocess.check_output(['ssh', self.remote_name, 'rm', remote_script_path], stderr=subprocess.STDOUT)
  239. except:
  240. logging.warn('Failed to delete remote \'{}\' script file'.format(remote_script_path))
  241. #
  242. #
  243. #
  244. #
  245. def build_circuit_generator(consensus, server_address):
  246. fingerprints = [desc.nickname for desc in consensus]
  247. exit_fingerprints = [desc.nickname for desc in consensus if desc.exit_policy.can_exit_to(*server_address)]
  248. authority_fingerprints = [desc.nickname for desc in consensus if desc.nickname.endswith('a')]
  249. #
  250. target_fingerprints = [desc.nickname for desc in consensus if desc.nickname.endswith('target')]
  251. assert len(target_fingerprints) >= 1, 'No target relay in the consensus'
  252. non_exit_fingerprints = list(set(fingerprints)-set(exit_fingerprints)-set(target_fingerprints)-set(authority_fingerprints))
  253. #
  254. assert len(exit_fingerprints) >= 1, 'Need at least one exit relay'
  255. assert len(non_exit_fingerprints) >= 1, 'Need at least one non-exit relay'
  256. #
  257. non_exit_fingerprints = sorted(non_exit_fingerprints)
  258. target_fingerprints = sorted(target_fingerprints)
  259. exit_fingerprints = sorted(exit_fingerprints)
  260. # try to get reproducible behavior
  261. #
  262. #return lambda gen_id=None: [random.choice(non_exit_fingerprints), target_fingerprint, random.choice(exit_fingerprints)]
  263. return lambda gen_id: [non_exit_fingerprints[gen_id%len(non_exit_fingerprints)], target_fingerprints[gen_id%len(target_fingerprints)], exit_fingerprints[gen_id%len(exit_fingerprints)]]
  264. '''
  265. fingerprints = [desc.fingerprint for desc in consensus]
  266. exit_fingerprints = [desc.fingerprint for desc in consensus if desc.exit_policy.can_exit_to(*server_address)]
  267. #
  268. target_fingerprint = [desc.fingerprint for desc in consensus if desc.nickname.endswith('target')][0]
  269. non_exit_fingerprints = list(set(fingerprints)-set(exit_fingerprints)-set([target_fingerprint]))
  270. #
  271. assert len(exit_fingerprints) >= 1, 'Need at least one exit relay'
  272. assert len(non_exit_fingerprints) >= 1, 'Need at least one non-exit relay'
  273. #
  274. #return lambda gen_id=None: [random.choice(non_exit_fingerprints), target_fingerprint, random.choice(exit_fingerprints)]
  275. return lambda gen_id: [non_exit_fingerprints[gen_id%len(non_exit_fingerprints)], target_fingerprint, exit_fingerprints[gen_id%len(exit_fingerprints)]]
  276. '''
  277. #
  278. def existing_file(path):
  279. if not os.path.isfile(path):
  280. raise argparse.ArgumentTypeError('The file path is not valid')
  281. return path
  282. #
  283. if __name__ == '__main__':
  284. #
  285. logging.basicConfig(level=logging.DEBUG)
  286. logging.getLogger('stem').setLevel(logging.WARNING)
  287. #
  288. parser = argparse.ArgumentParser(description='Test the network throughput.')
  289. parser.add_argument('num_bytes', type=useful.parse_bytes,
  290. help='number of bytes to send per connection (can also end with \'B\', \'KiB\', \'MiB\', or \'GiB\')', metavar='num-bytes')
  291. parser.add_argument('--buffer-len', type=useful.parse_bytes,
  292. help='size of the send and receive buffers (can also end with \'B\', \'KiB\', \'MiB\', or \'GiB\')', metavar='bytes')
  293. parser.add_argument('--wait-range', type=int, default=0,
  294. help='add a random wait time to each connection so that they don\'t all start at the same time (default is 0)', metavar='time')
  295. parser.add_argument('--target-tor', type=existing_file, default=None,
  296. help='use a different tor binary for the target', metavar='tor-path')
  297. parser.add_argument('--helgrind', action='store_true',
  298. help='log helgrind data')
  299. args = parser.parse_args()
  300. #
  301. #experiment_dir = '/var/ssd-raid/sengler/data/experiments'
  302. experiment_dir = '/home/sengler/data/experiments'
  303. #
  304. experiment_time = time.time()
  305. #base_save_data_path = os.path.join('/home/sengler/data/experiments', str(int(experiment_time)))
  306. base_save_data_path = os.path.join(experiment_dir, str(int(experiment_time)))
  307. os.mkdir(base_save_data_path)
  308. #
  309. measureme_log_path = None
  310. measureme = False
  311. #
  312. start_time = time.time()
  313. #
  314. #tors = {'working':'/home/sengler/code/working/tor/src/app/tor', 'working-without':'/home/sengler/code/working/tor-without-tcmalloc/src/app/tor', 'dev-without':'/home/sengler/code/dev/tor-throughput-log-0.4.2.6-without-tcmalloc/src/app/tor', 'dev-with':'/home/sengler/code/dev/tor-throughput-log-0.4.2.6-with-tcmalloc/src/app/tor'}
  315. #####tors = collections.OrderedDict()
  316. #####tors['working'] = '/home/sengler/code/working/tor/src/app/tor'
  317. #####tors['working-without'] = '/home/sengler/code/working/tor-without-tcmalloc/src/app/tor'
  318. #####tors['dev-with'] = '/home/sengler/code/dev/tor-throughput-log-0.4.2.6-with-tcmalloc/src/app/tor'
  319. #####tors['dev-without'] = '/home/sengler/code/dev/tor-throughput-log-0.4.2.6-without-tcmalloc/src/app/tor'
  320. ######hosts = ['sengler-rpi', 'cluck2']
  321. #####hosts = ['grunt3']
  322. ######hosts = ['sengler-rpi']
  323. #####num_repetitions = 15
  324. #####nums_additional_eventloops_options = [0, 1, 2, 3]
  325. ######nums_additional_eventloops_options = [3, 2, 1, 0]
  326. #tcmalloc_ld_preload = '/home/sengler/build/lib/libtcmalloc_and_profiler.so'
  327. tcmalloc_ld_preload = '/home/sengler/build/lib/libtcmalloc.so'
  328. jemalloc_ld_preload = '/home/sengler/build/lib/libjemalloc.so'
  329. tors = collections.OrderedDict()
  330. tors['multi-tcmalloc'] = ('/home/sengler/code/working/tor/src/app/tor', tcmalloc_ld_preload)
  331. tors['multi-jemalloc'] = ('/home/sengler/code/working/tor/src/app/tor', jemalloc_ld_preload)
  332. tors['multi-none'] = ('/home/sengler/code/working/tor/src/app/tor', None)
  333. tors['vanilla-tcmalloc'] = ('/home/sengler/code/dev/tor-0.4.2.6-throughput-log/src/app/tor', tcmalloc_ld_preload)
  334. tors['vanilla-jemalloc'] = ('/home/sengler/code/dev/tor-0.4.2.6-throughput-log/src/app/tor', jemalloc_ld_preload)
  335. tors['vanilla-none'] = ('/home/sengler/code/dev/tor-0.4.2.6-throughput-log/src/app/tor', None)
  336. configurations = {}
  337. configurations['broken'] = {'num_clients': 150,
  338. 'num_guards': 30, # number of relays (including guards)
  339. 'num_authorities': 2, # will also act as a relay or guard
  340. 'num_exits': 30, # will be used only as an exit
  341. 'num_streams_per_client': 10,
  342. 'num_bytes': 20*(2**20)}
  343. configurations['full-server'] = {'num_clients': 150,
  344. 'num_guards': 300, # number of relays (including guards)
  345. 'num_authorities': 3, # will also act as a relay or guard
  346. 'num_exits': 300, # will be used only as an exit
  347. 'num_streams_per_client': 10,
  348. 'num_bytes': 10*(2**20)}
  349. configurations['small-server'] = {'num_clients': 100,
  350. 'num_guards': 300, # number of relays (including guards)
  351. 'num_authorities': 3, # will also act as a relay or guard
  352. 'num_exits': 300, # will be used only as an exit
  353. 'num_streams_per_client': 6,
  354. 'num_bytes': 5*(2**20)}
  355. remotes = collections.OrderedDict()
  356. remotes['clack1'] = {'local_ip': '192.168.1.203',
  357. 'target_ip': '192.168.1.102',
  358. 'target_ssh': '192.168.1.102',
  359. 'target_chutney_net_dir': '/tmp/chutney-net',
  360. 'target_numa_settings': (0, [0, 32, 2, 34, 4, 36])}
  361. # 'target_cpu_prof': True}
  362. remotes['sengler-rpi'] = {'local_ip': '129.97.119.248',
  363. 'target_ip': '129.97.169.9',
  364. 'target_ssh': '129.97.169.9',
  365. 'target_chutney_net_dir': '/tmp/chutney-net',
  366. 'has_sudo': True}
  367. experiments = [('clack1', 'full-server'), ('sengler-rpi', 'small-server')]
  368. num_repetitions = 10
  369. nums_additional_eventloops_options = [0, 1, 2, 3]
  370. #nums_additional_eventloops_options = [3, 2, 1, 0]
  371. #
  372. #tors = {'working':'/home/sengler/code/working/tor/src/app/tor', 'dev-without':'/home/sengler/code/dev/tor-throughput-log-0.4.2.6-without-tcmalloc/src/app/tor'}
  373. #hosts = ['cluck2']
  374. #num_repetitions = 1
  375. #nums_additional_eventloops_options = [0, 1, 2, 3]
  376. #
  377. #tors = {'dev-debug-stall':'/home/sengler/code/dev/tor-throughput-log-0.4.2.6-debug-stall/src/app/tor'}
  378. #tors = {'dev-without':'/home/sengler/code/dev/tor-throughput-log-0.4.2.6-test-kist-changes/src/app/tor'}
  379. #tors = {'dev-without':'/home/sengler/code/dev/tor-throughput-log-0.4.2.6-without-tcmalloc/src/app/tor'}
  380. #hosts = ['cluck2']
  381. #num_repetitions = 5
  382. #nums_additional_eventloops_options = [3, 2, 1, 0]
  383. #
  384. try:
  385. for repeat in range(num_repetitions):
  386. for (remote_name, configuration_name) in experiments:
  387. remote_options = remotes[remote_name]
  388. configuration_options = configurations[configuration_name]
  389. #
  390. for (tor_name, (tor_path, tor_ld_preload)) in tors.items():
  391. num_clients = configuration_options['num_clients']
  392. num_guards = configuration_options['num_guards']
  393. num_authorities = configuration_options['num_authorities']
  394. num_exits = configuration_options['num_exits']
  395. num_streams_per_client = configuration_options['num_streams_per_client']
  396. num_bytes = configuration_options['num_bytes']
  397. #
  398. #num_clients = 4
  399. #num_guards = 6 # number of relays (including guards)
  400. #num_authorities = 2 # will also act as a relay or guard
  401. #num_exits = 8 # will be used only as an exit
  402. #num_streams_per_client = 1
  403. #if True:
  404. # num_clients = 4
  405. # num_guards = 10 # number of relays (including guards)
  406. # num_authorities = 2 # will also act as a relay or guard
  407. # num_exits = 12 # will be used only as an exit
  408. # num_streams_per_client = 3
  409. # num_bytes = 20*(2**20)
  410. '''
  411. if remote_name == 'cluck2':
  412. num_clients = 150
  413. num_guards = 30 # number of relays (including guards)
  414. num_authorities = 2 # will also act as a relay or guard
  415. num_exits = 30 # will be used only as an exit
  416. num_streams_per_client = 10
  417. num_bytes = 20*(2**20)
  418. elif remote_name == 'cluck15':
  419. num_clients = 150
  420. num_guards = 30 # number of relays (including guards)
  421. num_authorities = 2 # will also act as a relay or guard
  422. num_exits = 30 # will be used only as an exit
  423. num_streams_per_client = 10
  424. num_bytes = 20*(2**20)
  425. elif remote_name == 'grunt3':
  426. num_clients = 150
  427. num_guards = 30 # number of relays (including guards)
  428. num_authorities = 2 # will also act as a relay or guard
  429. num_exits = 30 # will be used only as an exit
  430. num_streams_per_client = 10
  431. num_bytes = 20*(2**20)
  432. elif remote_name == 'sengler-rpi':
  433. num_clients = 100
  434. num_guards = 300 # number of relays (including guards)
  435. num_authorities = 3 # will also act as a relay or guard
  436. num_exits = 300 # will be used only as an exit
  437. num_streams_per_client = 6
  438. num_bytes = 5*(2**20)
  439. elif remote_name is None:
  440. num_clients = 10
  441. num_guards = 10 # number of relays (including guards)
  442. num_authorities = 2 # will also act as a relay or guard
  443. num_exits = 12 # will be used only as an exit
  444. num_streams_per_client = 5
  445. num_bytes = 20*(2**20)
  446. else:
  447. raise Exception('remote not known')
  448. #
  449. '''
  450. nums_additional_eventloops = [0]
  451. if tor_name.startswith('multi'):
  452. nums_additional_eventloops = nums_additional_eventloops_options
  453. #
  454. for num_additional_eventloops in nums_additional_eventloops:
  455. attempt = 0
  456. while True:
  457. attempt_str = '' if attempt == 0 else '_attempt-{}'.format(attempt)
  458. save_data_path = os.path.join(base_save_data_path, '{}_{}_{}_{}{}'.format(remote_name, tor_name, num_additional_eventloops, repeat, attempt_str))
  459. os.mkdir(save_data_path)
  460. logging.info('Starting on {} using {}-{} ({}, {}), repeat {}, attempt {}'.format(remote_name, tor_name, num_additional_eventloops, tor_path, tor_ld_preload, repeat, attempt))
  461. #
  462. #exp = CustomExperiment(args.helgrind, args.target_tor, save_data_path, measureme_log_path, args.num_bytes,
  463. exp = CustomExperiment(args.helgrind, tor_path, tor_ld_preload, num_additional_eventloops, remote_name, remote_options, save_data_path,
  464. measureme_log_path, num_bytes,
  465. num_streams_per_client, num_clients, num_guards, num_authorities, num_exits,
  466. build_circuit_generator, args.buffer_len, args.wait_range, measureme, test_network=False)
  467. #
  468. def sleep_then_run(duration, func):
  469. logging.info('Sleeping for {} seconds before running \'{}\''.format(duration, func.__name__))
  470. time.sleep(duration)
  471. logging.info('Done sleeping')
  472. return func()
  473. #
  474. #import subprocess
  475. #p = subprocess.Popen(['ssh', '-t', 'sengler-rpi', 'python3 /tmp/log_system_usage.py /tmp/usage.gz'])
  476. #
  477. try:
  478. exp.start_chutney(lambda: exp.start_throughput_server(lambda: sleep_then_run(120, lambda: exp.start_system_logging(lambda: exp.start_remote_logging(exp.start_throughput_clients)))))
  479. except (stem.Timeout, stem.CircuitExtensionFailed, experiment.RepeatExperimentError):
  480. tries = 9
  481. attempt += 1
  482. if attempt < tries:
  483. logging.exception('Experiment run failed, trying again ({} tries remaining)'.format(tries-attempt))
  484. continue
  485. else:
  486. raise
  487. #
  488. #
  489. chutney_data_dir = os.getenv('CHUTNEY_DATA_DIR')
  490. assert chutney_data_dir is not None
  491. #
  492. os.system('rm -rf {}/nodes/*/diff-cache'.format(chutney_data_dir))
  493. os.system('rm -rf {}/nodes/*/keys'.format(chutney_data_dir))
  494. os.system('rm -f {}/nodes/*/cached-*'.format(chutney_data_dir))
  495. os.system('rm -f {}/nodes/*/v3-status-votes'.format(chutney_data_dir))
  496. shutil.copytree('{}/nodes'.format(chutney_data_dir), os.path.join(save_data_path, 'nodes'))
  497. os.system("ps u | grep 'tor'")
  498. os.system('rm -rf {}/*'.format(chutney_data_dir))
  499. break
  500. #
  501. exp = None
  502. gc.collect()
  503. # not sure if this is actually useful, but hopefully it reduces memory usage for when we need to fork
  504. #
  505. #
  506. #
  507. #
  508. except KeyboardInterrupt:
  509. logging.info('Stopped (KeyboardInterrupt)')
  510. #
  511. logging.info('Total time: {:.2f} minutes'.format((time.time()-start_time)/60))
  512. #