From: Erwan Velu Date: Wed, 16 Jun 2021 13:16:25 +0000 (+0200) Subject: tools: Adding fiograph X-Git-Tag: fio-3.28~49^2~1 X-Git-Url: https://git.kernel.dk/?p=fio.git;a=commitdiff_plain;h=d61215e076fe3b51c0ed92dd985101b84bbcd757 tools: Adding fiograph This tool generates graphviz graphs of any fio job file. Reading a fio file can be sometimes tricky when : - you have lots of jobs - jobs override some options - jobs have dependencies Understanding which jobs are running at the same time, which one waits for which is sometimes difficult and could easily lead to mistakes. It's pretty common to find jobs where people think jobs are sequential while some run in parallel. For ease the understanding of the scheduling and what's the configuration status (local + global variables), this tool will use some graphical helpers to enlighten things. The configuration file can be used to adjust the rendering but by default : - jobs are defined in a blue rounded box - jobs running at the same time are inside the same gray background - time & size variables are shown as a self arrow - dependencies between jobs are shown by up->down black arrows - specific engines options are written in blue (top of the job box) - standard options are printed in green (bottom of the job box) - pre/post actions are printed in red (head/tail of the job box) - numjobs is replaced by a 'x' multiplicator on the job name Several output formats can be defined via --format : list can be found here https://graphviz.org/docs/outputs/ if --view option is used, the rendered file will be immediately shown. if --keep is used, the grapvhiz file will be kept. This commit also adds the rendering of the examples jobs. If a newcomer gets into the repository, they can immediately better understand what the jobs do. Signed-off-by: Erwan Velu --- diff --git a/examples/1mbs_clients.png b/examples/1mbs_clients.png new file mode 100644 index 00000000..3f972dc6 Binary files /dev/null and b/examples/1mbs_clients.png differ diff --git a/examples/aio-read.png b/examples/aio-read.png new file mode 100644 index 00000000..e0c020a5 Binary files /dev/null and b/examples/aio-read.png differ diff --git a/examples/backwards-read.png b/examples/backwards-read.png new file mode 100644 index 00000000..81dc9208 Binary files /dev/null and b/examples/backwards-read.png differ diff --git a/examples/basic-verify.png b/examples/basic-verify.png new file mode 100644 index 00000000..98f73020 Binary files /dev/null and b/examples/basic-verify.png differ diff --git a/examples/butterfly.png b/examples/butterfly.png new file mode 100644 index 00000000..2c566512 Binary files /dev/null and b/examples/butterfly.png differ diff --git a/examples/cpp_null.png b/examples/cpp_null.png new file mode 100644 index 00000000..5303ac2a Binary files /dev/null and b/examples/cpp_null.png differ diff --git a/examples/cpuio.png b/examples/cpuio.png new file mode 100644 index 00000000..02938dbb Binary files /dev/null and b/examples/cpuio.png differ diff --git a/examples/cross-stripe-verify.png b/examples/cross-stripe-verify.png new file mode 100644 index 00000000..90aa630f Binary files /dev/null and b/examples/cross-stripe-verify.png differ diff --git a/examples/dev-dax.png b/examples/dev-dax.png new file mode 100644 index 00000000..2463bca3 Binary files /dev/null and b/examples/dev-dax.png differ diff --git a/examples/dfs.png b/examples/dfs.png new file mode 100644 index 00000000..049ccaec Binary files /dev/null and b/examples/dfs.png differ diff --git a/examples/disk-zone-profile.png b/examples/disk-zone-profile.png new file mode 100644 index 00000000..5f7b24c9 Binary files /dev/null and b/examples/disk-zone-profile.png differ diff --git a/examples/e4defrag.png b/examples/e4defrag.png new file mode 100644 index 00000000..00a7fefd Binary files /dev/null and b/examples/e4defrag.png differ diff --git a/examples/e4defrag2.png b/examples/e4defrag2.png new file mode 100644 index 00000000..8a128e95 Binary files /dev/null and b/examples/e4defrag2.png differ diff --git a/examples/enospc-pressure.png b/examples/enospc-pressure.png new file mode 100644 index 00000000..da28b7c0 Binary files /dev/null and b/examples/enospc-pressure.png differ diff --git a/examples/exitwhat.png b/examples/exitwhat.png new file mode 100644 index 00000000..9fc1883f Binary files /dev/null and b/examples/exitwhat.png differ diff --git a/examples/falloc.png b/examples/falloc.png new file mode 100644 index 00000000..886be22e Binary files /dev/null and b/examples/falloc.png differ diff --git a/examples/filecreate-ioengine.png b/examples/filecreate-ioengine.png new file mode 100644 index 00000000..45d11da3 Binary files /dev/null and b/examples/filecreate-ioengine.png differ diff --git a/examples/filedelete-ioengine.png b/examples/filedelete-ioengine.png new file mode 100644 index 00000000..3512ab71 Binary files /dev/null and b/examples/filedelete-ioengine.png differ diff --git a/examples/filestat-ioengine.png b/examples/filestat-ioengine.png new file mode 100644 index 00000000..bed59ab9 Binary files /dev/null and b/examples/filestat-ioengine.png differ diff --git a/examples/fio-rand-RW.png b/examples/fio-rand-RW.png new file mode 100644 index 00000000..aa4b0998 Binary files /dev/null and b/examples/fio-rand-RW.png differ diff --git a/examples/fio-rand-read.png b/examples/fio-rand-read.png new file mode 100644 index 00000000..d45664a4 Binary files /dev/null and b/examples/fio-rand-read.png differ diff --git a/examples/fio-rand-write.png b/examples/fio-rand-write.png new file mode 100644 index 00000000..10e068bc Binary files /dev/null and b/examples/fio-rand-write.png differ diff --git a/examples/fio-seq-RW.png b/examples/fio-seq-RW.png new file mode 100644 index 00000000..a2be35ec Binary files /dev/null and b/examples/fio-seq-RW.png differ diff --git a/examples/fio-seq-read.png b/examples/fio-seq-read.png new file mode 100644 index 00000000..cf8f2978 Binary files /dev/null and b/examples/fio-seq-read.png differ diff --git a/examples/fio-seq-write.png b/examples/fio-seq-write.png new file mode 100644 index 00000000..8db12092 Binary files /dev/null and b/examples/fio-seq-write.png differ diff --git a/examples/fixed-rate-submission.png b/examples/fixed-rate-submission.png new file mode 100644 index 00000000..86ca9b3e Binary files /dev/null and b/examples/fixed-rate-submission.png differ diff --git a/examples/flow.png b/examples/flow.png new file mode 100644 index 00000000..26a3d34c Binary files /dev/null and b/examples/flow.png differ diff --git a/examples/fsx.png b/examples/fsx.png new file mode 100644 index 00000000..b4e13c80 Binary files /dev/null and b/examples/fsx.png differ diff --git a/examples/ftruncate.png b/examples/ftruncate.png new file mode 100644 index 00000000..b98895f6 Binary files /dev/null and b/examples/ftruncate.png differ diff --git a/examples/gfapi.png b/examples/gfapi.png new file mode 100644 index 00000000..acc6a6ae Binary files /dev/null and b/examples/gfapi.png differ diff --git a/examples/gpudirect-rdmaio-client.png b/examples/gpudirect-rdmaio-client.png new file mode 100644 index 00000000..eac79858 Binary files /dev/null and b/examples/gpudirect-rdmaio-client.png differ diff --git a/examples/gpudirect-rdmaio-server.png b/examples/gpudirect-rdmaio-server.png new file mode 100644 index 00000000..e043d7c0 Binary files /dev/null and b/examples/gpudirect-rdmaio-server.png differ diff --git a/examples/http-s3.png b/examples/http-s3.png new file mode 100644 index 00000000..2021e85e Binary files /dev/null and b/examples/http-s3.png differ diff --git a/examples/http-swift.png b/examples/http-swift.png new file mode 100644 index 00000000..9928fb16 Binary files /dev/null and b/examples/http-swift.png differ diff --git a/examples/http-webdav.png b/examples/http-webdav.png new file mode 100644 index 00000000..c37c3de5 Binary files /dev/null and b/examples/http-webdav.png differ diff --git a/examples/ime.png b/examples/ime.png new file mode 100644 index 00000000..f636f5e7 Binary files /dev/null and b/examples/ime.png differ diff --git a/examples/iometer-file-access-server.png b/examples/iometer-file-access-server.png new file mode 100644 index 00000000..e3124554 Binary files /dev/null and b/examples/iometer-file-access-server.png differ diff --git a/examples/jesd219.png b/examples/jesd219.png new file mode 100644 index 00000000..73b5a124 Binary files /dev/null and b/examples/jesd219.png differ diff --git a/examples/latency-profile.png b/examples/latency-profile.png new file mode 100644 index 00000000..50650df8 Binary files /dev/null and b/examples/latency-profile.png differ diff --git a/examples/libcufile-cufile.png b/examples/libcufile-cufile.png new file mode 100644 index 00000000..f3758e5d Binary files /dev/null and b/examples/libcufile-cufile.png differ diff --git a/examples/libcufile-posix.png b/examples/libcufile-posix.png new file mode 100644 index 00000000..7818feb4 Binary files /dev/null and b/examples/libcufile-posix.png differ diff --git a/examples/libhdfs.png b/examples/libhdfs.png new file mode 100644 index 00000000..e774c911 Binary files /dev/null and b/examples/libhdfs.png differ diff --git a/examples/libiscsi.png b/examples/libiscsi.png new file mode 100644 index 00000000..d0006cc0 Binary files /dev/null and b/examples/libiscsi.png differ diff --git a/examples/libpmem.png b/examples/libpmem.png new file mode 100644 index 00000000..8a9a1432 Binary files /dev/null and b/examples/libpmem.png differ diff --git a/examples/librpma_apm-client.png b/examples/librpma_apm-client.png new file mode 100644 index 00000000..2fe02cdf Binary files /dev/null and b/examples/librpma_apm-client.png differ diff --git a/examples/librpma_apm-server.png b/examples/librpma_apm-server.png new file mode 100644 index 00000000..f78ae02e Binary files /dev/null and b/examples/librpma_apm-server.png differ diff --git a/examples/librpma_gpspm-client.png b/examples/librpma_gpspm-client.png new file mode 100644 index 00000000..0c975a27 Binary files /dev/null and b/examples/librpma_gpspm-client.png differ diff --git a/examples/librpma_gpspm-server.png b/examples/librpma_gpspm-server.png new file mode 100644 index 00000000..56124533 Binary files /dev/null and b/examples/librpma_gpspm-server.png differ diff --git a/examples/libzbc-rand-write.png b/examples/libzbc-rand-write.png new file mode 100644 index 00000000..1d277412 Binary files /dev/null and b/examples/libzbc-rand-write.png differ diff --git a/examples/libzbc-seq-read.png b/examples/libzbc-seq-read.png new file mode 100644 index 00000000..5a532228 Binary files /dev/null and b/examples/libzbc-seq-read.png differ diff --git a/examples/mtd.png b/examples/mtd.png new file mode 100644 index 00000000..8cb3692e Binary files /dev/null and b/examples/mtd.png differ diff --git a/examples/nbd.png b/examples/nbd.png new file mode 100644 index 00000000..e3bcf610 Binary files /dev/null and b/examples/nbd.png differ diff --git a/examples/netio.png b/examples/netio.png new file mode 100644 index 00000000..81afd41d Binary files /dev/null and b/examples/netio.png differ diff --git a/examples/netio_multicast.png b/examples/netio_multicast.png new file mode 100644 index 00000000..f07ab4b7 Binary files /dev/null and b/examples/netio_multicast.png differ diff --git a/examples/nfs.png b/examples/nfs.png new file mode 100644 index 00000000..29dbca0d Binary files /dev/null and b/examples/nfs.png differ diff --git a/examples/null.png b/examples/null.png new file mode 100644 index 00000000..052671db Binary files /dev/null and b/examples/null.png differ diff --git a/examples/numa.png b/examples/numa.png new file mode 100644 index 00000000..1ef45759 Binary files /dev/null and b/examples/numa.png differ diff --git a/examples/pmemblk.png b/examples/pmemblk.png new file mode 100644 index 00000000..250e254b Binary files /dev/null and b/examples/pmemblk.png differ diff --git a/examples/poisson-rate-submission.png b/examples/poisson-rate-submission.png new file mode 100644 index 00000000..739c2560 Binary files /dev/null and b/examples/poisson-rate-submission.png differ diff --git a/examples/rados.png b/examples/rados.png new file mode 100644 index 00000000..91bd61a0 Binary files /dev/null and b/examples/rados.png differ diff --git a/examples/rand-zones.png b/examples/rand-zones.png new file mode 100644 index 00000000..13cbfb47 Binary files /dev/null and b/examples/rand-zones.png differ diff --git a/examples/rbd.png b/examples/rbd.png new file mode 100644 index 00000000..f1186139 Binary files /dev/null and b/examples/rbd.png differ diff --git a/examples/rdmaio-client.png b/examples/rdmaio-client.png new file mode 100644 index 00000000..4e4bc289 Binary files /dev/null and b/examples/rdmaio-client.png differ diff --git a/examples/rdmaio-server.png b/examples/rdmaio-server.png new file mode 100644 index 00000000..fc344725 Binary files /dev/null and b/examples/rdmaio-server.png differ diff --git a/examples/ssd-steadystate.png b/examples/ssd-steadystate.png new file mode 100644 index 00000000..eb27f8a4 Binary files /dev/null and b/examples/ssd-steadystate.png differ diff --git a/examples/ssd-test.png b/examples/ssd-test.png new file mode 100644 index 00000000..a92ed153 Binary files /dev/null and b/examples/ssd-test.png differ diff --git a/examples/steadystate.png b/examples/steadystate.png new file mode 100644 index 00000000..4bb90484 Binary files /dev/null and b/examples/steadystate.png differ diff --git a/examples/surface-scan.png b/examples/surface-scan.png new file mode 100644 index 00000000..00573808 Binary files /dev/null and b/examples/surface-scan.png differ diff --git a/examples/test.png b/examples/test.png new file mode 100644 index 00000000..6be50029 Binary files /dev/null and b/examples/test.png differ diff --git a/examples/tiobench-example.png b/examples/tiobench-example.png new file mode 100644 index 00000000..14410326 Binary files /dev/null and b/examples/tiobench-example.png differ diff --git a/examples/waitfor.png b/examples/waitfor.png new file mode 100644 index 00000000..64e4bf94 Binary files /dev/null and b/examples/waitfor.png differ diff --git a/examples/zbd-rand-write.png b/examples/zbd-rand-write.png new file mode 100644 index 00000000..d58721be Binary files /dev/null and b/examples/zbd-rand-write.png differ diff --git a/examples/zbd-seq-read.png b/examples/zbd-seq-read.png new file mode 100644 index 00000000..b81a08c4 Binary files /dev/null and b/examples/zbd-seq-read.png differ diff --git a/examples/zipf.png b/examples/zipf.png new file mode 100644 index 00000000..cb2a9816 Binary files /dev/null and b/examples/zipf.png differ diff --git a/tools/fiograph/fiograph.conf b/tools/fiograph/fiograph.conf new file mode 100644 index 00000000..7b851e19 --- /dev/null +++ b/tools/fiograph/fiograph.conf @@ -0,0 +1,102 @@ +[fio_jobs] +header=< {} > +header_color=black +text_color=darkgreen +shape=box +shape_color=blue +style=rounded +title_style=< +item_style= +cluster_style=filled +cluster_color=gainsboro + +[exec_prerun] +text_color=red + +[exec_postrun] +text_color=red + +[numjobs] +text_color=red +style= x {} + +[ioengine] +text_color=darkblue +specific_options_color=darkblue + +# definitions of engine's specific options + +[ioengine_cpuio] +specific_options=cpuload cpumode cpuchunks exit_on_io_done + +[ioengine_dfs] +specific_options=pool cont chunk_size object_class svcl + +[ioengine_e4defrag] +specific_options=donorname inplace + +[ioengine_filestat] +specific_options=stat_type + +[ioengine_single-instance] +specific_options=volume brick + +[ioengine_http] +specific_options=https http_host http_user http_pass http_s3_key http_s3_keyid http_swift_auth_token http_s3_region http_mode http_verbose + +[ioengine_ime_aio] +specific_options=ime_psync ime_psyncv + +[ioengine_io_uring] +specific_options=hipri cmdprio_percentage cmdprio_percentage fixedbufs registerfiles sqthread_poll sqthread_poll_cpu nonvectored uncached nowait force_async + +[ioengine_libaio] +specific_options=userspace_reap cmdprio_percentage cmdprio_percentage nowait + +[ioengine_libcufile] +specific_options=gpu_dev_ids cuda_io + +[ioengine_libhdfs] +specific_options=namenode hostname port hdfsdirectory chunk_size single_instance hdfs_use_direct + +[ioengine_libiscsi] +specific_options=initiator + +[ioengine_librpma_apm_server] +specific_options=librpma_apm_client + +[ioengine_busy_wait_polling] +specific_options=serverip port direct_write_to_pmem + +[ioengine_librpma_gpspm_server] +specific_options=librpma_gpspm_client + +[ioengine_mmap] +specific_options=thp + +[ioengine_mtd] +specific_options=skip_bad + +[ioengine_nbd] +specific_options=uri + +[ioengine_net] +specific_options=hostname port protocol nodelay listen pingpong interface ttl window_size mss netsplice + +[ioengine_nfs] +specific_options=nfs_url + +[ioengine_rados] +specific_options=clustername pool clientname busy_poll touch_objects + +[ioengine_rbd] +specific_options=clustername rbdname pool clientname busy_poll + +[ioengine_rdma] +specific_options=hostname bindname port verb + +[ioengine_sg] +specific_options=hipri readfua writefua sg_write_mode sg + +[ioengine_pvsync2] +specific_options=hipri hipri_percentage uncached nowait sync psync vsync pvsync diff --git a/tools/fiograph/fiograph.py b/tools/fiograph/fiograph.py new file mode 100755 index 00000000..7695c964 --- /dev/null +++ b/tools/fiograph/fiograph.py @@ -0,0 +1,305 @@ +#!/usr/bin/env python3 +from graphviz import Digraph +import argparse +import configparser +import os + +config_file = None +fio_file = None + + +def get_section_option(section_name, option_name, default=None): + global fio_file + if fio_file.has_option(section_name, option_name): + return fio_file[section_name][option_name] + return default + + +def get_config_option(section_name, option_name, default=None): + global config_file + if config_file.has_option(section_name, option_name): + return config_file[section_name][option_name] + return default + + +def get_header_color(keyword='fio_jobs', default_color='black'): + return get_config_option(keyword, 'header_color', default_color) + + +def get_shape_color(keyword='fio_jobs', default_color='black'): + return get_config_option(keyword, 'shape_color', default_color) + + +def get_text_color(keyword='fio_jobs', default_color='black'): + return get_config_option(keyword, 'text_color', default_color) + + +def get_cluster_color(keyword='fio_jobs', default_color='gray92'): + return get_config_option(keyword, 'cluster_color', default_color) + + +def get_header(keyword='fio_jobs'): + return get_config_option(keyword, 'header') + + +def get_shape(keyword='fio_jobs'): + return get_config_option(keyword, 'shape', 'box') + + +def get_style(keyword='fio_jobs'): + return get_config_option(keyword, 'style', 'rounded') + + +def get_cluster_style(keyword='fio_jobs'): + return get_config_option(keyword, 'cluster_style', 'filled') + + +def get_specific_options(engine): + if not engine: + return '' + return get_config_option('ioengine_{}'.format(engine), 'specific_options', '').split(' ') + + +def render_option(section, label, display, option, color_override=None): + # These options are already shown with graphical helpers, no need to report them directly + skip_list = ['size', 'stonewall', 'runtime', 'time_based', + 'numjobs', 'wait_for', 'wait_for_previous'] + # If the option doesn't exist or if a special handling is already done + # don't render it, just return the current state + if option in skip_list or option not in section: + return label, display + display = option + if section[option]: + display = '{} = {}'.format(display, section[option]) + + # Adding jobs's options into the box, darkgreen is the default color + if color_override: + color = color_override + else: + color = get_text_color(option, get_text_color('fio_jobs', 'darkgreen')) + label += get_config_option('fio_jobs', + 'item_style').format(color, display) + return label, display + + +def render_options(fio_file, section_name): + """Render all options of a section.""" + display = section_name + section = fio_file[section_name] + + # Add a multiplier to the section_name if numjobs is set + numjobs = int(get_section_option(section_name, 'numjobs', '1')) + if numjobs > 1: + display = display + \ + get_style('numjobs').format( + get_text_color('numjobs'), numjobs) + + # Header of the box + label = get_config_option('fio_jobs', 'title_style').format(display) + + # Let's parse all the options of the current fio thread + # Some needs to be printed on top or bottom of the job to ease the read + to_early_print = ['exec_prerun', 'ioengine'] + to_late_print = ['exec_postrun'] + + # Let's print the options on top of the box + for early_print in to_early_print: + label, display = render_option( + section, label, display, early_print) + + current_io_engine = get_section_option( + section_name, 'ioengine', None) + if current_io_engine: + # Let's print all specifics options for this engine + for specific_option in sorted(get_specific_options(current_io_engine)): + label, display = render_option( + section, label, display, specific_option, get_config_option('ioengine', 'specific_options_color')) + + # Let's print generic options sorted by name + for option in sorted(section): + if option in to_early_print or option in to_late_print or option in get_specific_options(current_io_engine): + continue + label, display = render_option(section, label, display, option) + + # let's print options on the bottom of the box + for late_print in to_late_print: + label, display = render_option( + section, label, display, late_print) + + # End of the box content + label += '
{}
{}
>' + return label + + +def render_section(current_graph, fio_file, section_name, label): + """Render the section.""" + attr = None + section = fio_file[section_name] + + # Let's render the box associated to a job + current_graph.node(section_name, label, + shape=get_shape(), + color=get_shape_color(), + style=get_style()) + + # Let's report the duration of the jobs with a self-loop arrow + if 'runtime' in section and 'time_based' in section: + attr = 'runtime={}'.format(section['runtime']) + elif 'size' in section: + attr = 'size={}'.format(section['size']) + if attr: + current_graph.edge(section_name, section_name, attr) + + +def create_sub_graph(name): + """Return a new graph.""" + # We need to put 'cluster' in the name to ensure graphviz consider it as a cluster + cluster_name = 'cluster_' + name + # Unset the main graph labels to avoid a recopy in each subgraph + attr = {} + attr['label'] = '' + new_graph = Digraph(name=cluster_name, graph_attr=attr) + new_graph.attr(style=get_cluster_style(), + color=get_cluster_color()) + return new_graph + + +def create_legend(): + """Return a legend.""" + html_table = "<" + html_table += '' + legend_item = '"' + legend_bgcolor_item = '' + html_table += legend_item.format('numjobs', + get_text_color('numjobs'), 'x numjobs') + html_table += legend_item.format('generic option', + get_text_color(), 'generic option') + html_table += legend_item.format('ioengine option', + get_text_color('ioengine'), 'ioengine option') + html_table += legend_bgcolor_item.format('job', get_shape_color()) + html_table += legend_bgcolor_item.format( + 'execution group', get_cluster_color()) + html_table += '
Legend
{} {}
{}
>' + legend = Digraph('html_table') + legend.node('legend', shape='none', label=html_table) + return legend + + +def fio_to_graphviz(filename, format): + """Compute the graphviz graph from the fio file.""" + + # Let's read the fio file + global fio_file + fio_file = configparser.RawConfigParser( + allow_no_value=True, + default_section="global", + inline_comment_prefixes="'#', ';'") + fio_file.read(filename) + + # Prepare the main graph object + # Let's define the header of the document + attrs = {} + attrs['labelloc'] = 't' + attrs['label'] = get_header().format( + get_header_color(), os.path.basename(filename)) + main_graph = Digraph(engine='dot', graph_attr=attrs, format=format) + + # Let's add a legend + main_graph.subgraph(create_legend()) + + # By default all jobs are run in parallel and depends on "global" + depends_on = fio_file.default_section + + # The previous section is by default the global section + previous_section = fio_file.default_section + + current_graph = main_graph + + # The first job will be a new execution group + new_execution_group = True + + # Let's interate on all sections to create links between them + for section_name in fio_file.sections(): + # The current section + section = fio_file[section_name] + + # If the current section is waiting the previous job + if ('stonewall' or 'wait_for_previous') in section: + # let's remember what was the previous job we depend on + depends_on = previous_section + new_execution_group = True + elif 'wait_for' in section: + # This sections depends on a named section pointed by wait_for + depends_on = section['wait_for'] + new_execution_group = True + + if new_execution_group: + # Let's link the current graph with the main one + main_graph.subgraph(current_graph) + # Let's create a new graph to represent all the incoming jobs running at the same time + current_graph = create_sub_graph(section_name) + + # Let's render the current section in its execution group + render_section(current_graph, fio_file, section_name, + render_options(fio_file, section_name)) + + # Let's trace the link between this job and the one it depends on + # If we depend on 'global', we can avoid doing adding an arrow as we don't want to see 'global' + if depends_on != fio_file.default_section: + current_graph.edge(depends_on, section_name) + + # The current section become the parent of the next one + previous_section = section_name + + # We are by default in the same execution group + new_execution_group = False + + # The last subgraph isn't rendered yet + main_graph.subgraph(current_graph) + + # Let's return the main graphviz object + return main_graph + + +def setup_commandline(): + "Prepare the command line." + parser = argparse.ArgumentParser() + parser.add_argument('--file', action='store', + type=str, + required=True, + help='the fio file to graph') + parser.add_argument('--output', action='store', + type=str, + help='the output filename') + parser.add_argument('--format', action='store', + type=str, + default='png', + help='the output format') + parser.add_argument('--view', action='store_true', + default=False, + help='view the graph') + parser.add_argument('--keep', action='store_true', + default=False, + help='keep the graphviz script file') + parser.add_argument('--config', action='store', + type=str, + default='fiograph.conf', + help='the configuration filename') + args = parser.parse_args() + return args + + +def main(): + global config_file + args = setup_commandline() + output_file = args.file + if args.output is None: + output_file = output_file.replace('.fio', '') + config_file = configparser.RawConfigParser(allow_no_value=True) + config_file.read(args.config) + fio_to_graphviz(args.file, args.format).render(output_file, view=args.view) + if not args.keep: + os.remove(output_file) + + +main()