   ```
 
   """
-  @spec format(Suite.t) :: [any]
+  @spec format(Suite.t()) :: [any]
   def format(%Suite{scenarios: scenarios, configuration: config}) do
     config = console_configuration(config)
+
     scenarios
-    |> Enum.group_by(fn(scenario) -> scenario.input_name end)
-    |> Enum.map(fn({input, scenarios}) ->
-        [input_header(input) | format_scenarios(scenarios, config)]
-      end)
+    |> Enum.group_by(fn scenario -> scenario.input_name end)
+    |> Enum.map(fn {input, scenarios} ->
+      [
+        "Run time statistics:\n",
+        input_header(input),
+        format_scenarios(scenarios, config),
+        "\nMemory usage statistics:\n",
+        input_header(input),
+        format_scenarios_for_memory(scenarios, config)
+      ]
+    end)
   end
 
   @doc """
   Takes the output of `format/1` and writes that to the console.
   """
-  @spec write(any) :: :ok | {:error, String.t}
+  @spec write(any) :: :ok | {:error, String.t()}
   def write(output) do
     IO.write(output)
   rescue

    DeviationPercent.format(std_dev_ratio)
  end

  @spec comparison_report([Scenario.t], unit_per_statistic, integer, map)
    :: [String.t]
  defp comparison_report(scenarios, units, label_width, config)
  defp comparison_report([_scenario], _, _, _) do
    [] # No need for a comparison when only one benchmark was run
  end
  defp comparison_report(_, _, _, %{comparison: false}) do
    []
  end
  defp comparison_report([scenario | other_scenarios], units, label_width, _) do
    [
      descriptor("Comparison"),
      reference_report(scenario, units, label_width) |
      comparisons(scenario, units, label_width, other_scenarios)
    ]
  end

  defp reference_report(%Scenario{
                          name: name,
                          run_time_statistics: %Statistics{ips: ips}
                        },
                        %{ips: ips_unit}, label_width) do
    "~*s~*s\n"
    |> :io_lib.format([
         -label_width, name,
         @ips_width, ips_out(ips, ips_unit)])
    |> to_string
  end

  @spec comparisons(Scenario.t, unit_per_statistic, integer, [Scenario.t])
    :: [String.t]
  defp comparisons(%Scenario{run_time_statistics: reference_stats},
                   units, label_width, scenarios_to_compare) do
    Enum.map(scenarios_to_compare,
      fn(scenario = %Scenario{run_time_statistics: job_stats}) ->
        slower = (reference_stats.ips / job_stats.ips)
        format_comparison(scenario, units, label_width, slower)
      end
    )
  end

  defp format_comparison(%Scenario{
                           name: name,
                           run_time_statistics: %Statistics{ips: ips}},
                         %{ips: ips_unit}, label_width, slower) do
    ips_format = ips_out(ips, ips_unit)
    "~*s~*s - ~.2fx slower\n"
    |> :io_lib.format([
         -label_width, name,
         @ips_width, ips_format, slower])
    |> to_string
  end

  @spec descriptor(String.t) :: String.t
  defp descriptor(header_str) do
    "\n#{header_str}: \n"
  end

  ```

  """
  @spec format_scenarios([Scenario.t()], map) :: [String.t(), ...]
  def format_scenarios(scenarios, config) do
    sorted_scenarios = Statistics.sort(scenarios)
    %{unit_scaling: scaling_strategy} = config
    units = Conversion.units(sorted_scenarios, scaling_strategy)
    label_width = label_width(sorted_scenarios)

    [
      column_descriptors(label_width)
      | scenario_reports(sorted_scenarios, units, label_width) ++
          comparison_report(sorted_scenarios, units, label_width, config) ++
          extended_statistics_report(sorted_scenarios, units, label_width, config)
    ]
  end


  def format_scenarios_for_memory(scenarios, config) do
    sorted_scenarios = Statistics.sort(scenarios)
    #%{unit_scaling: scaling_strategy} = config
    units = %{memory: %Unit{label: "b", long: "byte", magnitude: 1, name: :byte}}
    label_width = label_width(sorted_scenarios)

    [
      column_descriptors_for_memory(label_width)
      | scenario_reports_for_memory(sorted_scenarios, units, label_width) ++
          comparison_report_for_memory(sorted_scenarios, units, label_width, config) ++
          extended_statistics_report(sorted_scenarios, units, label_width, config)
    ]
  end

  @spec extended_statistics_report([Scenario.t()], unit_per_statistic, integer, map) :: [
          String.t()
        ]
  defp extended_statistics_report(_, _, _, %{extended_statistics: false}) do
    []
  end

  defp extended_statistics_report(scenarios, units, label_width, _config) do
    [
      descriptor("Extended statistics"),
      extended_column_descriptors(label_width)
      | extended_statistics(scenarios, units, label_width)
    ]
  end

  @spec extended_statistics([Scenario.t()], unit_per_statistic, integer) :: [String.t()]
  defp extended_statistics(scenarios, units, label_width) do
    Enum.map(scenarios, fn scenario ->
      format_scenario_extended(scenario, units, label_width)
    end)
  end

  @spec format_scenario_extended(Scenario.t(), unit_per_statistic, integer) :: String.t()
  defp format_scenario_extended(
         %Scenario{
           name: name,
           run_time_statistics: %Statistics{
             minimum: minimum,
             maximum: maximum,
             sample_size: sample_size,
             mode: mode
           }
         },
         %{run_time: run_time_unit},
         label_width
       ) do
    "~*s~*ts~*ts~*ts~*ts\n"
    |> :io_lib.format([
      -label_width,
      name,
      @minimum_width,
      run_time_out(minimum, run_time_unit),
      @maximum_width,
      run_time_out(maximum, run_time_unit),
      @sample_size_width,
      Count.format(sample_size),
      @mode_width,
      mode_out(mode, run_time_unit)
    ])
    |> to_string
  end

  @spec mode_out(Statistics.mode(), Benchee.Conversion.Unit.t()) :: String.t()
  defp mode_out(modes, _run_time_unit) when is_nil(modes) do
    "None"
  end

  defp mode_out(modes, run_time_unit) when is_list(modes) do
    Enum.map_join(modes, ", ", fn mode -> run_time_out(mode, run_time_unit) end)
  end

  defp mode_out(mode, run_time_unit) when is_number(mode) do
    run_time_out(mode, run_time_unit)
  end

  @spec extended_column_descriptors(integer) :: String.t()
  defp extended_column_descriptors(label_width) do
    "\n~*s~*s~*s~*s~*s\n"
    |> :io_lib.format([
      -label_width,
      "Name",
      @minimum_width,
      "minimum",
      @maximum_width,
      "maximum",
      @sample_size_width,
      "sample size",
      @mode_width,
      "mode"
    ])
    |> to_string
  end

  @spec column_descriptors(integer) :: String.t()
  defp column_descriptors(label_width) do
    "\n~*s~*s~*s~*s~*s~*s\n"
    |> :io_lib.format([
      -label_width,
      "Name",
      @ips_width,
      "ips",
      @average_width,
      "average",
      @deviation_width,
      "deviation",
      @median_width,
      "median",
      @percentile_width,
      "99th %"
    ])
    |> to_string
  end

  defp column_descriptors_for_memory(label_width) do
    "\n~*s~*s~*s~*s~*s\n"
    |> :io_lib.format([
      -label_width,
      "Name",
      @average_width,
      "average",
      @deviation_width,
      "deviation",
      @median_width,
      "median",
      @percentile_width,
      "99th %"
    ])
    |> to_string
  end

  defp label_width(scenarios) do
    max_label_width =
      scenarios
      |> Enum.map(fn scenario -> String.length(scenario.name) end)
      |> Stream.concat([@default_label_width])
      |> Enum.max()

    max_label_width + 1
  end

  @spec scenario_reports([Scenario.t()], unit_per_statistic, integer) :: [String.t()]
  defp scenario_reports(scenarios, units, label_width) do
    Enum.map(scenarios, fn scenario ->
      format_scenario(scenario, units, label_width)
    end)
  end

  defp scenario_reports_for_memory(scenarios, units, label_width) do
    Enum.map(scenarios, fn scenario ->
      format_scenario_for_memory(scenario, units, label_width)
    end)
  end

  @spec format_scenario(Scenario.t(), unit_per_statistic, integer) :: String.t()
  defp format_scenario(
         %Scenario{
           name: name,
           run_time_statistics: %Statistics{
             average: average,
             ips: ips,
             std_dev_ratio: std_dev_ratio,
             median: median,
             percentiles: %{99 => percentile_99}
           }
         },
         %{run_time: run_time_unit, ips: ips_unit},
         label_width
       ) do
    "~*s~*ts~*ts~*ts~*ts~*ts\n"
    |> :io_lib.format([
      -label_width,
      name,
      @ips_width,
      ips_out(ips, ips_unit),
      @average_width,
      run_time_out(average, run_time_unit),
      @deviation_width,
      deviation_out(std_dev_ratio),
      @median_width,
      run_time_out(median, run_time_unit),
      @percentile_width,
      run_time_out(percentile_99, run_time_unit)
    ])
    |> to_string
  end

  defp format_scenario_for_memory(
         %Scenario{
           name: name,
           memory_usage_statistics: %Statistics{
             average: average,
             std_dev_ratio: std_dev_ratio,
             median: median,
             percentiles: %{99 => percentile_99}
           }
         },
         %{memory: memory_unit},
         label_width
       ) do
    "~*ts~*ts~*ts~*ts~*ts\n"
    |> :io_lib.format([
      -label_width,
      name,
      @average_width,
      run_time_out(average, memory_unit),
      @deviation_width,
      deviation_out(std_dev_ratio),
      @median_width,
      run_time_out(median, memory_unit),
      @percentile_width,
      run_time_out(percentile_99, memory_unit)
    ])
    |> to_string
  end

