-
Notifications
You must be signed in to change notification settings - Fork 265
Several misc. fixes, cleanups, features #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e7fdb64
e34ea11
5ba4f0b
6e4474d
67b769a
f9b0adf
66f7158
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,62 +1,74 @@ | ||
| # Where to plot and log | ||
| # Where to plot and log. | ||
| directories: | ||
| # One directory for logs | ||
| # One directory in which to store all plot job logs (the STDOUT/ | ||
| # STDERR of all plot jobs). In order to monitor progress, plotman | ||
| # reads these logs on a regular basis, so using a fast drive is | ||
| # recommended. | ||
| log: /home/chia/chia/logs | ||
|
|
||
| # One or more directories; the scheduler will use all of them | ||
| # One or more directories to use as tmp dirs for plotting. The | ||
| # scheduler will use all of them and distribute jobs among them. | ||
| # It assumes that IO is independent for each one (i.e., that each | ||
| # one is on a different physical device). | ||
| # | ||
| # If multiple directories share a common prefix, reports will | ||
| # abbreviate and show just the uniquely identifying suffix. | ||
| tmp: | ||
| - /mnt/tmp/00 | ||
| - /mnt/tmp/01 | ||
| - /mnt/tmp/02 | ||
| - /mnt/tmp/03 | ||
| - /mnt/tmp/04 | ||
| - /mnt/tmp/05 | ||
| - /mnt/tmp/06 | ||
| - /mnt/tmp/07 | ||
| - /mnt/tmp/08 | ||
| - /mnt/tmp/09 | ||
| - /mnt/tmp/10 | ||
| - /mnt/tmp/11 | ||
|
|
||
| # One directory (TODO: support distributing across multiple tmp2 dirs) | ||
| tmp2: /mnt/tmp/a | ||
|
|
||
| # One or more directories; the scheduler will use all of them | ||
|
|
||
| # Optional: tmp2 directory. If specified, will be passed to | ||
| # chia plots create as -2. Only one tmp2 directory is supported. | ||
| # tmp2: /mnt/tmp/a | ||
|
|
||
| # One or more directories; the scheduler will use all of them. | ||
| # These again are presumed to be on independent physical devices, | ||
| # so writes (plot jobs) and reads (archivals) can be scheduled | ||
| # to minimize IO contention. | ||
| dst: | ||
| - /home/chia/chia/plots/000 | ||
| - /home/chia/chia/plots/001 | ||
| - /home/chia/chia/plots/002 | ||
| - /home/chia/chia/plots/003 | ||
| - /mnt/dst/00 | ||
| - /mnt/dst/01 | ||
|
|
||
| # Archival | ||
| # Archival configuration. Optional. | ||
| # | ||
| # Currently archival depends on an rsync daemon running on the remote | ||
| # host, and that the module is configured to match the local path. | ||
| # See code for details. | ||
| archive: | ||
| rsyncd_module: plots | ||
| rsyncd_path: /plots | ||
| rsyncd_bwlimit: 100000 # In KB/s | ||
| rsyncd_host: farmer | ||
| rsyncd_bwlimit: 80000 # Bandwidth limit in KB/s | ||
| rsyncd_host: myfarmer | ||
| rsyncd_user: chia | ||
|
|
||
|
|
||
| # Plotting scheduling parameters | ||
| scheduling: | ||
| # Don't run a job on a particular temp dir more often than this. | ||
| # (obsolete) | ||
| # tmpdir_stagger_m: 300 | ||
| # Don't run a job on a particular temp dir until all existing jobs | ||
| # have progresed at least this far. Phase major corresponds to the | ||
| # plot phase, phase minor corresponds to the table or table pair | ||
| # in sequence. | ||
| tmpdir_stagger_phase_major: 2 | ||
| tmpdir_stagger_phase_minor: 5 | ||
| tmpdir_stagger_phase_minor: 1 | ||
|
|
||
| # Don't run more than this many jobs at a time on a single temp dir. | ||
| tmpdir_max_jobs: 3 | ||
|
|
||
| # Global min; don't run any jobs more often than this. | ||
| # Don't run any jobs (across all temp dirs) more often than this. | ||
| global_stagger_m: 30 | ||
|
|
||
| # How often the daemon wakes to consider starting a new plot job | ||
| polling_time_s: 20 | ||
|
|
||
| # Plotting parameters | ||
|
|
||
| # Plotting parameters. These are pass-through parameters to chia plots create. | ||
| # See documentation at | ||
| # https://github.com/Chia-Network/chia-blockchain/wiki/CLI-Commands-Reference#create | ||
| plotting: | ||
| k: 32 | ||
| e: True # Use -e plotting option | ||
| n_threads: 8 # Threads per job | ||
| # n_buckets: 64 # Number of buckets to split data into | ||
| # job_buffer: 9200 # Per job memory | ||
| n_buckets: 128 # Number of buckets to split data into | ||
| job_buffer: 4580 # Per job memory | ||
| job_buffer: 4520 # Per job memory |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |||||
| import archive | ||||||
| import job | ||||||
| import manager | ||||||
| import math | ||||||
| import plot_util | ||||||
|
|
||||||
| def abbr_path(path, putative_prefix): | ||||||
|
|
@@ -13,9 +14,49 @@ def abbr_path(path, putative_prefix): | |||||
| else: | ||||||
| return path | ||||||
|
|
||||||
| def phases_str(phases): | ||||||
| def phases_str(phases, max_num=None): | ||||||
| '''Take a list of phase-subphase pairs and return them as a compact string''' | ||||||
| return ', '.join(['%d:%d' % ph_subph for ph_subph in phases]) | ||||||
| if not max_num or len(phases) <= max_num: | ||||||
| return ' '.join(['%d:%d' % pair for pair in phases]) | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I won't bother changing all the |
||||||
| else: | ||||||
| n_first = math.floor(max_num / 2) | ||||||
| n_last = max_num - n_first | ||||||
| n_elided = len(phases) - (n_first + n_last) | ||||||
| first = ' '.join(['%d:%d' % pair for pair in phases[:n_first]]) | ||||||
| elided = " [+%d] " % n_elided | ||||||
| last = ' '.join(['%d:%d' % pair for pair in phases[n_first + n_elided:]]) | ||||||
| return first + elided + last | ||||||
|
|
||||||
| def n_at_ph(jobs, ph): | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't abbreviate much, probably to a fault.
Suggested change
|
||||||
| return sum([1 for j in jobs if j.progress() == ph]) | ||||||
|
|
||||||
| def n_to_char(n): | ||||||
| n_to_char_map = dict(enumerate(" .:;!")) | ||||||
|
|
||||||
| if n < 0: | ||||||
| return 'X' # Should never be negative | ||||||
| elif n >= len(n_to_char_map): | ||||||
| n = len(n_to_char_map) - 1 | ||||||
|
|
||||||
| return n_to_char_map[n] | ||||||
|
|
||||||
| def job_viz(jobs): | ||||||
| # TODO: Rewrite this in a way that ensures we count every job | ||||||
| # even if the reported phases don't line up with expectations. | ||||||
| result = '' | ||||||
| result += '1' | ||||||
| for i in range(0, 8): | ||||||
| result += n_to_char(n_at_ph(jobs, (1, i))) | ||||||
| result += '2' | ||||||
| for i in range(0, 8): | ||||||
| result += n_to_char(n_at_ph(jobs, (2, i))) | ||||||
| result += '3' | ||||||
| for i in range(0, 7): | ||||||
| result += n_to_char(n_at_ph(jobs, (3, i))) | ||||||
| result += '4' | ||||||
| result += n_to_char(n_at_ph(jobs, (4, 0))) | ||||||
| return result | ||||||
|
|
||||||
|
|
||||||
| def status_report(jobs, width, height=None, tmp_prefix='', dst_prefix=''): | ||||||
| '''height, if provided, will limit the number of rows in the table, | ||||||
|
|
@@ -103,7 +144,7 @@ def dst_dir_report(jobs, dstdirs, width, prefix=''): | |||||
| tab = tt.Texttable() | ||||||
| dir2oldphase = manager.dstdirs_to_furthest_phase(jobs) | ||||||
| dir2newphase = manager.dstdirs_to_youngest_phase(jobs) | ||||||
| headings = ['dst', 'plots', 'GB free', 'phases', 'priority'] | ||||||
| headings = ['dst', 'plots', 'GBfree', 'inbnd phases', 'pri'] | ||||||
| tab.header(headings) | ||||||
| tab.set_cols_dtype('t' * len(headings)) | ||||||
|
|
||||||
|
|
@@ -117,7 +158,8 @@ def dst_dir_report(jobs, dstdirs, width, prefix=''): | |||||
| gb_free = int(plot_util.df_b(d) / plot_util.GB) | ||||||
| n_plots = len(dir_plots) | ||||||
| priority = archive.compute_priority(eldest_ph, gb_free, n_plots) | ||||||
| row = [abbr_path(d, prefix), n_plots, gb_free, phases_str(phases), priority] | ||||||
| row = [abbr_path(d, prefix), n_plots, gb_free, | ||||||
| phases_str(phases, 5), priority] | ||||||
| tab.add_row(row) | ||||||
| tab.set_max_width(width) | ||||||
| tab.set_deco(tt.Texttable.BORDER | tt.Texttable.HEADER ) | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| #!/usr/bin/python3 | ||
|
|
||
| from unittest.mock import patch | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I very rarely mock.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As in, you rarely need to, or there's another mechanism you prefer, or you structure your code so you don't need mock-style mechanisms?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I try to avoid the need. I see tests as a second use of your code. If it's hard to test, it can mean your code isn't as flexible as it ought to be. So yeah, different code structure often. Lots of details to discuss in each actual case. |
||
|
|
||
| import os | ||
| import pyfakefs | ||
| import unittest | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I always use pytest.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, OK, added an issue to consider switching to pytest. |
||
|
|
||
| import reporting | ||
|
|
||
| class TestReporting(unittest.TestCase): | ||
| def test_phases_str(self): | ||
| self.assertEqual('1:2 2:3 3:4 4:0', | ||
| reporting.phases_str([(1,2), (2,3), (3,4), (4,0)])) | ||
| self.assertEqual('1:2 [+1] 3:4 4:0', | ||
| reporting.phases_str([(1,2), (2,3), (3,4), (4,0)], 3)) | ||
| self.assertEqual('1:2 [+2] 4:0', | ||
| reporting.phases_str([(1,2), (2,3), (3,4), (4,0)], 2)) | ||
|
|
||
| def test_job_viz_empty(self): | ||
| self.assertEqual('1 2 3 4 ', | ||
| reporting.job_viz([]) ) | ||
|
|
||
| @patch('job.Job') | ||
| def job_w_phase(self, ph, MockJob): | ||
| j = MockJob() | ||
| j.progress.return_value = ph | ||
| return j | ||
|
|
||
| def test_job_viz_positions(self): | ||
| jobs = [self.job_w_phase((1, 1)), | ||
| self.job_w_phase((2, 0)), | ||
| self.job_w_phase((2, 4)), | ||
| self.job_w_phase((2, 7)), | ||
| self.job_w_phase((4, 0))] | ||
|
|
||
| self.assertEqual('1 . 2. . .3 4.', | ||
| reporting.job_viz(jobs)) | ||
|
|
||
| def test_job_viz_counts(self): | ||
| jobs = [self.job_w_phase((2, 2)), | ||
| self.job_w_phase((2, 3)), | ||
| self.job_w_phase((2, 3)), | ||
| self.job_w_phase((2, 4)), | ||
| self.job_w_phase((2, 4)), | ||
| self.job_w_phase((2, 4)), | ||
| self.job_w_phase((2, 5)), | ||
| self.job_w_phase((2, 5)), | ||
| self.job_w_phase((2, 5)), | ||
| self.job_w_phase((2, 5)), | ||
| self.job_w_phase((3, 1)), | ||
| self.job_w_phase((3, 1)), | ||
| self.job_w_phase((3, 1)), | ||
| self.job_w_phase((3, 1)), | ||
| self.job_w_phase((3, 1)), | ||
| self.job_w_phase((3, 1)), | ||
| ] | ||
|
|
||
| self.assertEqual('1 2 .:;! 3 ! 4 ', | ||
| reporting.job_viz(jobs)) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Call this taste, but... I am relatively in the camp of 'turning other things into booleans is not great'. For example, lots of people will
if some_list:while I willif len(some_list) > 0:because, well... It is more explicit and shows issues sooner ifsome_list == Noneor such. Others could argue this better than me. But certainly, lots of people do leverage the truthiness of lots of non-boolean objects.