diff --git a/erp5/util/benchmark/report.py b/erp5/util/benchmark/report.py
index 44847a6546b9b4f6cbd670780ec6b06f031a7d08..58b77806c18c520374c9852e343850c7684fb8b4 100755
--- a/erp5/util/benchmark/report.py
+++ b/erp5/util/benchmark/report.py
@@ -117,10 +117,17 @@ def computeStatisticFromFilenameList(argument_namespace, filename_list,
           if suite_name in use_case_suite_dict:
             continue
 
-          use_case_suite_dict[suite_name] = {'duration_stats': [],
+          duration_stat_list = []
+
+          use_case_suite_dict[suite_name] = {'duration_stats': duration_stat_list,
                                              'count_stats': []}
 
           row_use_case_mapping_dict[index] = suite_name
+
+          if is_range_user:
+            report_dict['use_cases'].append({
+                'count': 0,
+                'duration_stats': duration_stat_list})
         else:
           if argument_namespace.do_merge_label:
             if label in merged_label_dict:
@@ -135,7 +142,8 @@ def computeStatisticFromFilenameList(argument_namespace, filename_list,
           if is_range_user:
             report_dict = range_user_report_dict.setdefault(
               suite_name,
-              {'results': collections.OrderedDict()})
+              {'results': collections.OrderedDict(),
+               'use_cases': []})          
 
             report_dict['results'].setdefault(stat.full_label, []).append(stat)
 
@@ -179,6 +187,12 @@ def computeStatisticFromFilenameList(argument_namespace, filename_list,
 
           stat_count.add(current_count)
           stat_duration.add(current_duration)
+
+          # For total stats, used later on to generate the number of
+          # cases/hour per users
+          if is_range_user:
+            total_dict = range_user_report_dict[use_case_suite]['use_cases'][-1]
+            total_dict['count'] += current_count
         else:
           index = merged_label_dict.get(label_list[idx], idx)
           stat_list[index].add(float(row))
@@ -368,6 +382,72 @@ def drawUseCasePerNumberOfUserPlot(axes,
           ticker.MultipleLocator(use_case_count_max * 2),
           ticker.MultipleLocator(use_case_count_max))
 
+@drawPlotDecorator(xlabel='Concurrent Users',
+                   ylabel='Use cases/h')
+def drawConcurrentUsersUseCasePlot(axes,
+                                    nb_users_list,
+                                    use_case_stat_list):
+  use_case_per_hour_min_list = []
+  use_case_per_hour_mean_list = []
+  use_case_per_hour_max_list = []
+
+  y_error_lower_list = []
+  y_error_upper_list = []
+
+  for use_case_stat in use_case_stat_list:
+    count = use_case_stat['count']
+
+    maximum_sum = 0
+    mean_sum = 0
+    minimum_sum = 0
+    stddev = 0
+    for stat in use_case_stat['duration_stats']:
+      minimum_sum += stat.minimum / 60.0
+      mean_sum += stat.mean / 60.0
+      maximum_sum += stat.maximum / 60.0
+      stddev = max(stddev, stat.standard_deviation / 60.0)
+
+    use_case_per_hour_min = count / maximum_sum
+    use_case_per_hour_min_list.append(use_case_per_hour_min)
+
+    use_case_per_hour_mean = count / mean_sum
+    use_case_per_hour_mean_list.append(use_case_per_hour_mean)
+
+    use_case_per_hour_max = count / minimum_sum
+    use_case_per_hour_max_list.append(use_case_per_hour_max)
+
+    if stddev:
+      y_error_lower = use_case_per_hour_mean - max(use_case_per_hour_min,
+                                                   count / (mean_sum + stddev))
+
+      y_error_upper = min(use_case_per_hour_max,
+                          count / (mean_sum - stddev)) - use_case_per_hour_mean
+    else:
+      y_error_lower = y_error_upper = 0
+
+    y_error_lower_list.append(y_error_lower)
+    y_error_upper_list.append(y_error_upper)
+
+  axes.plot(nb_users_list, use_case_per_hour_min_list, 'yo-', label='Minimum')
+
+  axes.errorbar(nb_users_list,
+                use_case_per_hour_mean_list,
+                yerr=[y_error_lower_list, y_error_upper_list],
+                color='r',
+                ecolor='b',
+                label='Mean',
+                elinewidth=2,
+                fmt='D-',
+                capsize=10.0)
+
+  axes.plot(nb_users_list, use_case_per_hour_max_list, 'gs-', label='Maximum')
+
+  axes.set_xticks(nb_users_list)
+  pyplot.xlim(xmin=nb_users_list[0], xmax=nb_users_list[-1])
+
+  return (ticker.FixedLocator(nb_users_list), None,
+          ticker.MaxNLocator(nbins=20), ticker.AutoMinorLocator()) 
+
 @drawPlotDecorator(xlabel='Concurrent users',
                    ylabel='Seconds')
 def drawConcurrentUsersPlot(axes, nb_users_list, stat_list):
@@ -458,10 +538,9 @@ def generateReport():
 
   if is_range_user:
     nb_users_list = per_nb_users_report_dict.keys()
-    title_fmt = "%%s from %d to %d users (step: %d)" % \
+    title_fmt = "%%s from %d to %d users" % \
         (nb_users_list[0],
-         nb_users_list[-1],
-         nb_users_list[1] - nb_users_list[0])
+         nb_users_list[-1])
 
     for suite_name, report_dict in range_user_report_dict.iteritems():
       for label, stat_list in report_dict['results'].iteritems():
@@ -471,6 +550,12 @@ def generateReport():
           nb_users_list,
           stat_list)
 
+      drawConcurrentUsersUseCasePlot(
+        pdf,
+        title_fmt % ("%s: Use cases" % suite_name),
+        nb_users_list,
+        report_dict['use_cases'])
+
   pdf.close()
 
 if __name__ == '__main__':