plots.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. # MODULE: grass.benchmark
  2. #
  3. # AUTHOR(S): Vaclav Petras <wenzeslaus gmail com>
  4. #
  5. # PURPOSE: Benchmarking for GRASS GIS modules
  6. #
  7. # COPYRIGHT: (C) 2021 Vaclav Petras, and by the GRASS Development Team
  8. #
  9. # This program is free software under the GNU General Public
  10. # License (>=v2). Read the file COPYING that comes with GRASS
  11. # for details.
  12. """Plotting functionality for benchmark results"""
  13. def get_pyplot(to_file):
  14. """Get pyplot from matplotlib
  15. Lazy import to easily run code importing this function on limited installations.
  16. Only actual call to this function requires matplotlib.
  17. The *to_file* parameter can be set to True to avoid tkinter dependency
  18. if the interactive show method is not needed.
  19. """
  20. import matplotlib # pylint: disable=import-outside-toplevel
  21. if to_file:
  22. backend = "agg"
  23. else:
  24. backend = None
  25. if backend:
  26. matplotlib.use(backend)
  27. import matplotlib.pyplot as plt # pylint: disable=import-outside-toplevel
  28. return plt
  29. def nprocs_plot(results, filename=None, title=None):
  30. """Plot results from a multiple nprocs (thread) benchmarks.
  31. *results* is a list of individual results from separate benchmarks.
  32. One result is required to have attributes: *nprocs*, *times*, *label*.
  33. The *nprocs* attribute is a list of all processing elements
  34. (cores, threads, processes) used in the benchmark.
  35. The *times* attribute is a list of corresponding times for each value
  36. from the *nprocs* list.
  37. The *label* attribute identifies the benchmark in the legend.
  38. Optionally, result can have an *all_times* attribute which is a list
  39. of lists. One sublist is all times recorded for each value of nprocs.
  40. Each result can come with a different list of nprocs, i.e., benchmarks
  41. which used different values for nprocs can be combined in one plot.
  42. """
  43. plt = get_pyplot(to_file=bool(filename))
  44. axes = plt.gca()
  45. x_ticks = set() # gather x values
  46. for result in results:
  47. x = result.nprocs
  48. x_ticks.update(x)
  49. plt.plot(x, result.times, label=result.label)
  50. if hasattr(result, "all_times"):
  51. mins = [min(i) for i in result.all_times]
  52. maxes = [max(i) for i in result.all_times]
  53. plt.fill_between(x, mins, maxes, color="gray", alpha=0.3)
  54. plt.legend()
  55. # If there is not many x values, show ticks for each, but use default
  56. # ticks when there is a lot of x values.
  57. if len(x_ticks) < 10:
  58. axes.set(xticks=sorted(x_ticks))
  59. else:
  60. from matplotlib.ticker import ( # pylint: disable=import-outside-toplevel
  61. MaxNLocator,
  62. )
  63. axes.xaxis.set_major_locator(MaxNLocator(integer=True))
  64. plt.xlabel("Number of processing elements (cores, threads, processes)")
  65. plt.ylabel("Time [s]")
  66. if title:
  67. plt.title(title)
  68. else:
  69. plt.title("Execution time by processing elements")
  70. if filename:
  71. plt.savefig(filename)
  72. else:
  73. plt.show()
  74. def num_cells_plot(results, filename=None, title=None, show_resolution=False):
  75. """Plot results from a multiple raster grid size benchmarks.
  76. *results* is a list of individual results from separate benchmarks
  77. with one result being similar to the :func:`nprocs_plot` function.
  78. The result is required to have *times* and *label* attributes
  79. and may have an *all_times* attribute.
  80. Further, it is required to have *cells* attribute, or,
  81. when ``show_resolution=True``, it needs to have a *resolutions* attribute.
  82. Each result can come with a different list of nprocs, i.e., benchmarks
  83. which used different values for nprocs can be combined in one plot.
  84. """
  85. plt = get_pyplot(to_file=bool(filename))
  86. axes = plt.gca()
  87. if show_resolution:
  88. axes.invert_xaxis()
  89. x_ticks = set()
  90. for result in results:
  91. if show_resolution:
  92. x = result.resolutions
  93. else:
  94. x = result.cells
  95. x_ticks.update(x)
  96. plt.plot(x, result.times, label=result.label)
  97. if hasattr(result, "all_times"):
  98. mins = [min(i) for i in result.all_times]
  99. maxes = [max(i) for i in result.all_times]
  100. plt.fill_between(x, mins, maxes, color="gray", alpha=0.3)
  101. plt.legend()
  102. axes.set(xticks=sorted(x_ticks))
  103. if not show_resolution:
  104. axes.ticklabel_format(axis="x", style="scientific", scilimits=(0, 0))
  105. if show_resolution:
  106. plt.xlabel("Resolution [map units]")
  107. else:
  108. plt.xlabel("Number of cells")
  109. plt.ylabel("Time [s]")
  110. if title:
  111. plt.title(title)
  112. elif show_resolution:
  113. plt.title("Execution time by resolution")
  114. else:
  115. plt.title("Execution time by cell count")
  116. if filename:
  117. plt.savefig(filename)
  118. else:
  119. plt.show()