Commit 449699af authored by Maiterth, Matthias's avatar Maiterth, Matthias
Browse files

Merge remote-tracking branch 'origin/gantt-plot' into scheduler-statistics

parents e6302750 80e2c7c5
Loading
Loading
Loading
Loading
+17 −2
Original line number Diff line number Diff line
@@ -110,12 +110,27 @@ See instructions in [server/README.md](https://code.ornl.gov/exadigit/simulation

See instructions in [dashboard/README.md](https://code.ornl.gov/exadigit/simulation-dashboard)

## Authors:
## Authors

Many thanks to the contributors of ExaDigiT/RAPS.  
The full list of contributors and organizations involved are found in CONTRIBUTORS.txt.  

## License:
## Citation

If you use ExaDigiT or RAPS in your research, please cite our work:

    @inproceedings{inproceedings,
      title={ExaDigiT: A Framework for Digital Twins of Liquid-cooled Supercomputers Demonstrating Comprehensive Modeling of Workloads, Power, and Cooling},
      author={Brewer, W. and Dash, S. and Maiterth, S. and Greenwood, S. and Shin, W. and Grant, D. and others},
      booktitle={SC24: International Conference for High Performance Computing, Networking, Storage and Analysis},
      pages={1--18},
      year={2024},
      organization={IEEE}
    }

Thank you for your support!

## License

ExaDigiT/RAPS is distributed under the terms of both the MIT license and the Apache License (Version 2.0).  
Users may choose either license, at their option.  
+52 −0
Original line number Diff line number Diff line
@@ -231,6 +231,58 @@ def plot_submit_times(submit_times, nr_list):
    plt.savefig('submit_times.png', dpi=300, bbox_inches='tight')


def convert_time_scale(times):
    max_time = max(times)
    if max_time >= 3600 * 24 * 7:  # more than a week
        return [t / (3600 * 24) for t in times], 'days'
    elif max_time >= 3600 * 24:    # more than a day
        return [t / 3600 for t in times], 'hours'
    else:
        return times, 'seconds'


def plot_job_gantt(start_times, end_times, node_counts):
    # Convert times
    start_times, time_label = convert_time_scale(start_times)
    end_times, _ = convert_time_scale(end_times)

    plt.figure(figsize=(10, 4))

    # We'll plot each job in a different row on the Y-axis
    y_positions = range(len(start_times))  # 0, 1, 2, ...
    
    for s, e, n in zip(start_times, end_times, node_counts):
        # Bar placed at y = n
        plt.barh(
            y=n,                # node count is the vertical coordinate
            width=e - s,        # job duration on the x-axis
            left=s,             # start time
            height=0.8,         # thickness of the bar
            color='yellow', 
            edgecolor='black', 
            alpha=0.8
        )

    #for y, (s, e, n) in enumerate(zip(start_times, end_times, node_counts)):
    #    plt.barh(y, width=e - s, left=s, height=0.8,
    #                 color='yellow', edgecolor='black', alpha=0.8)
    #    # Optionally place the node count label in the middle of the bar
    #    plt.text((s + e)/2, y, str(n),
    #             ha='center', va='center', color='black')

    plt.xlabel(f'Time ({time_label})')
    plt.ylabel('Job Index')
    plt.title('Job Timeline (Gantt Style)')
    plt.yticks(y_positions)  # label each job if desired

    # Time axis from earliest start to latest end
    plt.xlim(min(start_times), max(end_times))

    plt.tight_layout()
    plt.savefig('job_gantt.png', dpi=300)
    plt.show()


if __name__ == "__main__":
    plotter = Plotter()
    #plotter.plot_history([1, 2, 3, 4])
+7 −3
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ if __name__ == "__main__":
                        help='Either: path/to/joblive path/to/jobprofile' + \
                             ' -or- filename.npz (overrides --workload option)')
    parser.add_argument('-p', '--plot', action='store_true', help='Output plots')
    parser.add_argument('-t', '--time', type=str, default=None, help='Length of time to simulate, e.g., 123, 123s, 27m, 3h, 7d')
    parser.add_argument('--system', type=str, default='frontier', help='System config to use')
    choices = ['prescribed', 'poisson']
    parser.add_argument('--arrival', default=choices[0], type=str, choices=choices, help=f'Modify arrival distribution ({choices[1]}) or use the original submit times ({choices[0]})')
@@ -29,7 +30,7 @@ from tqdm import tqdm
from .config import ConfigManager
from .job import Job
from .account import Accounts
from .plotting import plot_submit_times, plot_nodes_histogram
from .plotting import plot_submit_times, plot_nodes_histogram, plot_job_gantt
from .utils import next_arrival


@@ -98,12 +99,14 @@ if __name__ == "__main__":
    wt_list = []
    nr_list = []
    submit_times = []
    end_times = []
    last = 0
    for job_vector in jobs:
        job = Job(job_vector)
        wt_list.append(job.wall_time)
        nr_list.append(job.nodes_required)
        submit_times.append(job.submit_time)
        end_times.append(job.submit_time + job.wall_time)
        if job.submit_time > 0:
            dt = job.submit_time - last
            dt_list.append(dt)
@@ -119,5 +122,6 @@ if __name__ == "__main__":
    print(f'Nodes required (std): {np.std(nr_list):.2f}')

    if args.plot:
        plot_nodes_histogram(nr_list)
        plot_submit_times(submit_times, nr_list)
        #plot_nodes_histogram(nr_list)
        #plot_submit_times(submit_times, nr_list)
        plot_job_gantt(submit_times, end_times, nr_list)