4 <title>Cluster report for xzzz1 from 2024-04-04 to 2024-04-06</title>
7 <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.min.js"></script>
8 <script type="text/javascript">
9 var chartdata = [{"label": "Concurrent running containers", "charts": [{"data": [[new Date("2024-04-06T11:00:00Z"), 3], [new Date("2024-04-06T11:05:00Z"), 5], [new Date("2024-04-06T11:10:00Z"), 2], [new Date("2024-04-06T11:15:00Z"), 5], [new Date("2024-04-06T11:20:00Z"), 3]], "options": {"legend": "always", "connectSeparatedPoints": true, "labels": ["date", "containers"], "includeZero": true, "title": "Concurrent running containers"}}]}, {"label": "Data under management", "charts": [{"data": [[new Date("2024-04-06T11:00:00Z"), 3], [new Date("2024-04-06T11:05:00Z"), 5], [new Date("2024-04-06T11:10:00Z"), 2], [new Date("2024-04-06T11:15:00Z"), 5], [new Date("2024-04-06T11:20:00Z"), 3]], "options": {"legend": "always", "connectSeparatedPoints": true, "labels": ["date", "managed"], "includeZero": true, "title": "Data under management"}}]}, {"label": "Storage usage", "charts": [{"data": [[new Date("2024-04-06T11:00:00Z"), 3], [new Date("2024-04-06T11:05:00Z"), 5], [new Date("2024-04-06T11:10:00Z"), 2], [new Date("2024-04-06T11:15:00Z"), 5], [new Date("2024-04-06T11:20:00Z"), 3]], "options": {"legend": "always", "connectSeparatedPoints": true, "labels": ["date", "used"], "includeZero": true, "title": "Storage usage"}}]}];
10 // Copyright (c) 2009 Dan Vanderkam. All rights reserved.
12 // SPDX-License-Identifier: MIT
15 * Synchronize zooming and/or selections between a set of dygraphs.
19 * var g1 = new Dygraph(...),
20 * g2 = new Dygraph(...),
22 * var sync = Dygraph.synchronize(g1, g2, ...);
23 * // charts are now synchronized
25 * // charts are no longer synchronized
27 * You can set options using the last parameter, for example:
29 * var sync = Dygraph.synchronize(g1, g2, g3, {
34 * The default is to synchronize both of these.
36 * Instead of passing one Dygraph object as each parameter, you may also pass an
39 * var sync = Dygraph.synchronize([g1, g2, g3], {
44 * You may also set `range: false` if you wish to only sync the x-axis.
45 * The `range` option has no effect unless `zoom` is true (the default).
47 * Original source: https://github.com/danvk/dygraphs/blob/master/src/extras/synchronizer.js
48 * at commit b55a71d768d2f8de62877c32b3aec9e9975ac389
50 * Copyright (c) 2009 Dan Vanderkam
52 * Permission is hereby granted, free of charge, to any person
53 * obtaining a copy of this software and associated documentation
54 * files (the "Software"), to deal in the Software without
55 * restriction, including without limitation the rights to use,
56 * copy, modify, merge, publish, distribute, sublicense, and/or sell
57 * copies of the Software, and to permit persons to whom the
58 * Software is furnished to do so, subject to the following
61 * The above copyright notice and this permission notice shall be
62 * included in all copies or substantial portions of the Software.
64 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
65 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
66 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
67 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
68 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
69 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
70 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
71 * OTHER DEALINGS IN THE SOFTWARE.
74 /* global Dygraph:false */
79 Dygraph = window.Dygraph;
80 } else if (typeof(module) !== 'undefined') {
81 Dygraph = require('../dygraph');
84 var synchronize = function(/* dygraphs..., opts */) {
85 if (arguments.length === 0) {
86 throw 'Invalid invocation of Dygraph.synchronize(). Need >= 1 argument.';
89 var OPTIONS = ['selection', 'zoom', 'range'];
96 var prevCallbacks = [];
98 var parseOpts = function(obj) {
99 if (!(obj instanceof Object)) {
100 throw 'Last argument must be either Dygraph or Object.';
102 for (var i = 0; i < OPTIONS.length; i++) {
103 var optName = OPTIONS[i];
104 if (obj.hasOwnProperty(optName)) opts[optName] = obj[optName];
109 if (arguments[0] instanceof Dygraph) {
110 // Arguments are Dygraph objects.
111 for (var i = 0; i < arguments.length; i++) {
112 if (arguments[i] instanceof Dygraph) {
113 dygraphs.push(arguments[i]);
118 if (i < arguments.length - 1) {
119 throw 'Invalid invocation of Dygraph.synchronize(). ' +
120 'All but the last argument must be Dygraph objects.';
121 } else if (i == arguments.length - 1) {
122 parseOpts(arguments[arguments.length - 1]);
124 } else if (arguments[0].length) {
125 // Invoked w/ list of dygraphs, options
126 for (var i = 0; i < arguments[0].length; i++) {
127 dygraphs.push(arguments[0][i]);
129 if (arguments.length == 2) {
130 parseOpts(arguments[1]);
131 } else if (arguments.length > 2) {
132 throw 'Invalid invocation of Dygraph.synchronize(). ' +
133 'Expected two arguments: array and optional options argument.';
134 } // otherwise arguments.length == 1, which is fine.
136 throw 'Invalid invocation of Dygraph.synchronize(). ' +
137 'First parameter must be either Dygraph or list of Dygraphs.';
140 if (dygraphs.length < 2) {
141 throw 'Invalid invocation of Dygraph.synchronize(). ' +
142 'Need two or more dygraphs to synchronize.';
145 var readycount = dygraphs.length;
146 for (var i = 0; i < dygraphs.length; i++) {
148 g.ready( function() {
149 if (--readycount == 0) {
150 // store original callbacks
151 var callBackTypes = ['drawCallback', 'highlightCallback', 'unhighlightCallback'];
152 for (var j = 0; j < dygraphs.length; j++) {
153 if (!prevCallbacks[j]) {
154 prevCallbacks[j] = {};
156 for (var k = callBackTypes.length - 1; k >= 0; k--) {
157 prevCallbacks[j][callBackTypes[k]] = dygraphs[j].getFunctionOption(callBackTypes[k]);
161 // Listen for draw, highlight, unhighlight callbacks.
163 attachZoomHandlers(dygraphs, opts, prevCallbacks);
166 if (opts.selection) {
167 attachSelectionHandlers(dygraphs, prevCallbacks);
175 for (var i = 0; i < dygraphs.length; i++) {
178 g.updateOptions({drawCallback: prevCallbacks[i].drawCallback});
180 if (opts.selection) {
182 highlightCallback: prevCallbacks[i].highlightCallback,
183 unhighlightCallback: prevCallbacks[i].unhighlightCallback
187 // release references & make subsequent calls throw.
190 prevCallbacks = null;
195 function arraysAreEqual(a, b) {
196 if (!Array.isArray(a) || !Array.isArray(b)) return false;
198 if (i !== b.length) return false;
200 if (a[i] !== b[i]) return false;
205 function attachZoomHandlers(gs, syncOpts, prevCallbacks) {
207 for (var i = 0; i < gs.length; i++) {
210 drawCallback: function(me, initial) {
211 if (block || initial) return;
214 dateWindow: me.xAxisRange()
216 if (syncOpts.range) opts.valueRange = me.yAxisRange();
218 for (var j = 0; j < gs.length; j++) {
220 if (prevCallbacks[j] && prevCallbacks[j].drawCallback) {
221 prevCallbacks[j].drawCallback.apply(this, arguments);
226 // Only redraw if there are new options
227 if (arraysAreEqual(opts.dateWindow, gs[j].getOption('dateWindow')) &&
228 arraysAreEqual(opts.valueRange, gs[j].getOption('valueRange'))) {
232 gs[j].updateOptions(opts);
236 }, true /* no need to redraw */);
240 function attachSelectionHandlers(gs, prevCallbacks) {
242 for (var i = 0; i < gs.length; i++) {
246 highlightCallback: function(event, x, points, row, seriesName) {
250 for (var i = 0; i < gs.length; i++) {
252 if (prevCallbacks[i] && prevCallbacks[i].highlightCallback) {
253 prevCallbacks[i].highlightCallback.apply(this, arguments);
257 var idx = gs[i].getRowForX(x);
259 gs[i].setSelection(idx, seriesName);
264 unhighlightCallback: function(event) {
268 for (var i = 0; i < gs.length; i++) {
270 if (prevCallbacks[i] && prevCallbacks[i].unhighlightCallback) {
271 prevCallbacks[i].unhighlightCallback.apply(this, arguments);
275 gs[i].clearSelection();
279 }, true /* no need to redraw */);
283 Dygraph.synchronize = synchronize;
287 // Copyright (C) The Arvados Authors. All rights reserved.
289 // SPDX-License-Identifier: AGPL-3.0
291 window.onload = function() {
296 if (y > 1000000000000000) { y=y/1000000000000000; s='P'; }
297 else if (y > 1000000000000) { y=y/1000000000000; s='T'; }
298 else if (y > 1000000000) { y=y/1000000000; s='G'; }
299 else if (y > 1000000) { y=y/1000000; s='M'; }
300 else if (y > 1000) { y=y/1000; s='K'; }
301 return y.toFixed(2).replace(/\.0+$/, '')+s;
305 if (s >= 86400) ret += Math.floor(s/86400) + 'd'
306 if (s >= 3600) ret += Math.floor(s/3600)%24 + 'h'
307 if (s >= 60) ret += Math.floor(s/60)%60 + 'm'
308 ret += Math.floor(s)%60 + 's'
309 // finally, strip trailing zeroes: 1d0m0s -> 1d
310 return ret.replace(/(\D)(0\D)*$/, '$1')
312 date: function(s, opts, sth, dg, idk, excludeHour) {
313 var date = new Date(s);
314 var options = {month: 'numeric', day: 'numeric'};
316 options.hour = 'numeric';
317 options.minute = 'numeric';
318 options.hour12 = false;
320 var r = new Intl.DateTimeFormat(undefined, options).format(date);
325 time: function(min, max, pixels, opts, dg) {
326 var max_ticks = Math.floor(pixels / (opts('axisLabelWidth')+opts('pixelsPerLabel')/2))
327 var natural = [1, 5, 10, 30, 60,
328 120, 300, 600, 1800, 3600,
329 7200, 14400, 43200, 86400]
330 var interval = natural.shift()*1000
331 while (max>min && (max-min)/interval > max_ticks) {
332 interval = (natural.shift()*1000) || (interval * 2)
335 var excludeHour = false;
336 var date = new Date(min);
337 // need to take the seconds since midnight and then round off to the nearest interval.
338 var millisecondsSinceMidnight = (date.getHours() * 3600 + date.getMinutes() * 60 + date.getSeconds()) * 1000;
339 if (interval >= 86400000) {
342 var roundedOff = Math.ceil(millisecondsSinceMidnight/interval)*interval;
343 min = (min - millisecondsSinceMidnight) + roundedOff;
345 //for (var i=Math.ceil(min/interval)*interval; i<=max; i+=interval) {
346 for (var i=min; i<=max; i+=interval) {
347 ticks.push({v: i, label: opts('axisLabelFormatter')(i, opts, "", false, false, excludeHour)})
352 chartdata.forEach(function(section, section_idx) {
353 var chartDiv = document.getElementById("chart");
354 section.charts.forEach(function(chart, chart_idx) {
355 // Skip chart if every series has zero data points
356 if (0 == chart.data.reduce(function(len, series) {
357 return len + series.length;
361 var id = 'chart-'+section_idx+'-'+chart_idx;
362 var div = document.createElement('div');
363 div.setAttribute('id', id);
364 div.setAttribute('style', 'width: 100%; height: 250px');
365 chartDiv.appendChild(div);
366 chart.options.valueFormatter = function(y) {
368 chart.options.axes = {
370 axisLabelFormatter: fmt.date,
371 valueFormatter: fmt.date,
377 axisLabelFormatter: fmt.iso,
378 valueFormatter: fmt.iso,
381 var div2 = document.createElement('div');
382 div2.setAttribute('style', 'width: 150px; height: 250px');
383 chart.options.labelsDiv = div2;
384 chart.options.labelsSeparateLines = true;
386 var div3 = document.createElement('div');
387 div3.setAttribute('style', 'display: flex; padding-bottom: 16px');
388 div3.appendChild(div);
389 div3.appendChild(div2);
390 chartDiv.appendChild(div3);
392 charts[id] = new Dygraph(div, chart.data, chart.options);
396 var sync = Dygraph.synchronize(Object.values(charts), {range: false});
398 if (typeof window.debug === 'undefined')
400 window.debug.charts = charts;
404 * Copyright Jonas Earendel. All rights reserved.
405 * SPDX-License-Identifier: Unlicense
409 * https://www.npmjs.com/package/sortable-tablesort
410 * https://github.com/tofsjonas/sortable
412 * Makes html tables sortable, No longer ie9+ 😢
414 * Styling is done in css.
416 * Copyleft 2017 Jonas Earendel
418 * This is free and unencumbered software released into the public domain.
420 * Anyone is free to copy, modify, publish, use, compile, sell, or
421 * distribute this software, either in source code form or as a compiled
422 * binary, for any purpose, commercial or non-commercial, and by any
425 * In jurisdictions that recognize copyright laws, the author or authors
426 * of this software dedicate any and all copyright interest in the
427 * software to the public domain. We make this dedication for the benefit
428 * of the public at large and to the detriment of our heirs and
429 * successors. We intend this dedication to be an overt act of
430 * relinquishment in perpetuity of all present and future rights to this
431 * software under copyright law.
433 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
434 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
435 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
436 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
437 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
438 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
439 * OTHER DEALINGS IN THE SOFTWARE.
441 * For more information, please refer to <http://unlicense.org>
444 document.addEventListener('click', function (e) {
446 // allows for elements inside TH
447 function findElementRecursive(element, tag) {
448 return element.nodeName === tag ? element : findElementRecursive(element.parentNode, tag);
450 var ascending_table_sort_class = 'asc';
451 var no_sort_class = 'no-sort';
452 var null_last_class = 'n-last';
453 var table_class_name = 'sortable';
454 var alt_sort_1 = e.shiftKey || e.altKey;
455 var element = findElementRecursive(e.target, 'TH');
456 var tr = element.parentNode;
457 var thead = tr.parentNode;
458 var table = thead.parentNode;
459 function getValue(element) {
461 var value = alt_sort_1 ? element.dataset.sortAlt : (_a = element.dataset.sort) !== null && _a !== void 0 ? _a : element.textContent;
464 if (thead.nodeName === 'THEAD' && // sortable only triggered in `thead`
465 table.classList.contains(table_class_name) &&
466 !element.classList.contains(no_sort_class) // .no-sort is now core functionality, no longer handled in CSS
469 var nodes = tr.cells;
470 var tiebreaker_1 = +element.dataset.sortTbr;
471 // Reset thead cells and get column index
472 for (var i = 0; i < nodes.length; i++) {
473 if (nodes[i] === element) {
474 column_index_1 = +element.dataset.sortCol || i;
477 nodes[i].setAttribute('aria-sort', 'none');
480 var direction = 'descending';
481 if (element.getAttribute('aria-sort') === 'descending' ||
482 (table.classList.contains(ascending_table_sort_class) && element.getAttribute('aria-sort') !== 'ascending')) {
483 direction = 'ascending';
485 // Update the `th` class accordingly
486 element.setAttribute('aria-sort', direction);
487 var reverse_1 = direction === 'ascending';
488 var sort_null_last_1 = table.classList.contains(null_last_class);
489 var compare_1 = function (a, b, index) {
490 var x = getValue(b.cells[index]);
491 var y = getValue(a.cells[index]);
492 if (sort_null_last_1) {
493 if (x === '' && y !== '') {
496 if (y === '' && x !== '') {
500 // Before comparing, clean up formatted numbers that may have a leading dollar sign and/or commas.
501 x = x.replace("$", "").replace(",", "");
502 y = y.replace("$", "").replace(",", "");
504 var bool = isNaN(temp) ? x.localeCompare(y) : temp;
505 return reverse_1 ? -bool : bool;
507 // loop through all tbodies and sort them
508 for (var i = 0; i < table.tBodies.length; i++) {
509 var org_tbody = table.tBodies[i];
510 // Put the array rows in an array, so we can sort them...
511 var rows = [].slice.call(org_tbody.rows, 0);
512 // Sort them using Array.prototype.sort()
513 rows.sort(function (a, b) {
514 var bool = compare_1(a, b, column_index_1);
515 return bool === 0 && !isNaN(tiebreaker_1) ? compare_1(a, b, tiebreaker_1) : bool;
517 // Make an empty clone
518 var clone_tbody = org_tbody.cloneNode();
519 // Put the sorted rows inside the clone
520 clone_tbody.append.apply(clone_tbody, rows);
521 // And finally replace the unsorted tbody with the sorted one
522 table.replaceChild(clone_tbody, org_tbody);
525 // eslint-disable-next-line no-unused-vars
528 // console.log(error)
538 font-family: "Roboto", "Helvetica", "Arial", sans-serif;
540 color: rgba(0, 0, 0, 0.87);
545 box-shadow: 0px 1px 5px 0px rgba(0,0,0,0.2),0px 2px 2px 0px rgba(0,0,0,0.14),0px 3px 1px -2px rgba(0,0,0,0.12);
550 padding: 2px 16px 8px 16px;
561 border-top: 1px solid rgba(224, 224, 224, 1);
565 border-top: 1px solid rgba(224, 224, 224, 1);
575 .sortable thead th:not(.no-sort) {
578 .sortable thead th:not(.no-sort)::after, .sortable thead th:not(.no-sort)::before {
579 transition: color 0.1s ease-in-out;
583 .sortable thead th:not(.no-sort)::after {
587 .sortable thead th:not(.no-sort):hover::after {
590 .sortable thead th:not(.no-sort)[aria-sort=descending]::after {
594 .sortable thead th:not(.no-sort)[aria-sort=ascending]::after {
598 .sortable thead th:not(.no-sort).indicator-left::after {
601 .sortable thead th:not(.no-sort).indicator-left::before {
605 .sortable thead th:not(.no-sort).indicator-left:hover::before {
608 .sortable thead th:not(.no-sort).indicator-left[aria-sort=descending]::before {
612 .sortable thead th:not(.no-sort).indicator-left[aria-sort=ascending]::before {
617 table.aggtable td:nth-child(2) {
621 table.active-projects td:nth-child(4),
622 table.active-projects td:nth-child(5) {
627 table.single-project td:nth-child(3),
628 table.single-project td:nth-child(4) {
633 table.active-projects th:nth-child(4),
634 table.active-projects th:nth-child(5) {
638 table.project td:nth-child(3),
639 table.project td:nth-child(4),
640 table.project td:nth-child(5),
641 table.project td:nth-child(6),
642 table.project td:nth-child(7) {
647 table.project th:nth-child(3),
648 table.project th:nth-child(4),
649 table.project th:nth-child(5),
650 table.project th:nth-child(6),
651 table.project th:nth-child(7) {
656 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/dygraph/2.0.0/dygraph.min.css">
665 <div class="content">
666 <h1>Cluster report for xzzz1 from 2024-04-04 to 2024-04-06</h1>
672 <div class="content">
673 <h2>Cluster status as of 2024-04-06</h2>
674 <table class='aggtable'><tbody>
675 <tr><th><a href="https://xzzz1.arvadosapi.com/users">Total users</a></th><td>4</td></tr>
676 <tr><th>Total projects</th><td>6</td></tr>
678 <tr><th>Total data under management</th> <td>0.003 KB</td></tr>
679 <tr><th>Total storage usage</th> <td>0.003 KB</td></tr>
680 <tr><th>Deduplication ratio</th> <td>1.0</td></tr>
681 <tr><th>Approximate monthly storage cost</th> <td>$0.00</td></tr>
684 <p>See <a href="#prices">note on usage and cost calculations</a> for details on how costs are calculated.</p>
690 <div class="content">
691 <h2>Activity and cost over the 2 day period 2024-04-04 to 2024-04-06</h2>
692 <table class='aggtable'><tbody>
693 <tr><th>Active users</th> <td>1</td></tr>
694 <tr><th><a href="#Active_Projects">Active projects</a></th> <td>1</td></tr>
695 <tr><th>Workflow runs</th> <td>1</td></tr>
696 <tr><th>Compute used</th> <td>1.5 hours</td></tr>
697 <tr><th>Compute cost</th> <td>$0.23</td></tr>
698 <tr><th>Storage cost</th> <td>$0.00</td></tr>
700 <p>See <a href="#prices">note on usage and cost calculations</a> for details on how costs are calculated.</p>
706 <div class="content">
708 <div id="chart"></div>
714 <div class="content">
716 <a id="Active_Projects"><h2>Active Projects</h2></a>
717 <table class='sortable active-projects'>
718 <thead><tr><th>Project</th> <th>Users</th> <th>Active</th> <th>Compute usage (hours)</th> <th>Compute cost</th> </tr></thead>
719 <tbody><tr><td><a href="#WGS chr19 test for 2.7.2~rc3">WGS chr19 test for 2.7.2~rc3</a></td><td>User1</td> <td>2024-04-05 to 2024-08-22</td> <td>1.5</td> <td>$0.23</td></tr></tbody>
721 <p>See <a href="#prices">note on usage and cost calculations</a> for details on how costs are calculated.</p>
727 <div class="content">
728 <a id="WGS chr19 test for 2.7.2~rc3"></a><a href="https://xzzz1.arvadosapi.com/projects/pirca-j7d0g-cukk4aw4iamj90c"><h2>WGS chr19 test for 2.7.2~rc3</h2></a>
730 <table class='sortable single-project'>
731 <thead><tr> <th>Users</th> <th>Active</th> <th>Compute usage (hours)</th> <th>Compute cost</th> </tr></thead>
732 <tbody><tr><td>User1</td> <td>2024-04-05 to 2024-08-22</td> <td>1.5</td> <td>$0.23</td></tr></tbody>
735 <table class='sortable project'>
736 <thead><tr><th>Workflow run count</th> <th>Workflow name</th> <th>Median runtime</th> <th>Mean runtime</th> <th>Median cost per run</th> <th>Mean cost per run</th> <th>Sum cost over runs</th></tr></thead>
739 <tr><td>1</td> <td>WGS processing workflow scattered over samples (v1.1-2-gcf002b3)</td> <td>1:19:21</td> <td>1:19:21</td> <td>$1.37</td> <td>$1.37</td> <td>$1.37</td></tr>
747 <div class="content">
749 <h2 id="prices">Note on usage and cost calculations</h2>
751 <div style="max-width: 60em">
753 <p>The numbers presented in this report are estimates and will
754 not perfectly match your cloud bill. Nevertheless this report
755 should be useful for identifying your main cost drivers.</p>
759 <p>"Total data under management" is what you get if you add up
760 all blocks referenced by all collections in Workbench, without
761 considering deduplication.</p>
763 <p>"Total storage usage" is the actual underlying storage
764 usage, accounting for data deduplication.</p>
766 <p>Storage costs are based on AWS "S3 Standard"
767 described on the <a href="https://aws.amazon.com/s3/pricing/">Amazon S3 pricing</a> page:</p>
770 <li>$0.023 per GB / Month for the first 50 TB</li>
771 <li>$0.022 per GB / Month for the next 450 TB</li>
772 <li>$0.021 per GB / Month over 500 TB</li>
775 <p>Finally, this only the base storage cost, and does not
776 include any fees associated with S3 API usage. However, there
777 are generally no ingress/egress fees if your Arvados instance
778 and S3 bucket are in the same region, which is the normal
779 recommended configuration.</p>
783 <p>"Compute usage" are instance-hours used in running
784 workflows. Because multiple steps may run in parallel on
785 multiple instances, a workflow that completes in four hours
786 but runs parallel steps on five instances, would be reported
787 as using 20 instance hours.</p>
789 <p>"Runtime" is the actual wall clock time that it took to
790 complete a workflow. This does not include time spent in the
791 queue for the workflow itself, but does include queuing time
792 of individual workflow steps.</p>
794 <p>Computational costs are derived from Arvados cost
795 calculations of container runs. For on-demand instances, this
796 uses the prices from the InstanceTypes section of the Arvado
797 config file, set by the system administrator. For spot
798 instances, this uses current spot prices retrieved on the fly
801 <p>Be aware that the cost calculations are only for the time
802 the container is running and only do not take into account the
803 overhead of launching instances or idle time between scheduled
804 tasks or prior to automatic shutdown.</p>