write_prometheus plugin: Improve performance of metric_cmp().
authorFlorian Forster <octo@collectd.org>
Sat, 1 Oct 2016 19:22:12 +0000 (21:22 +0200)
committerFlorian Forster <octo@collectd.org>
Fri, 11 Nov 2016 13:42:03 +0000 (14:42 +0100)
This function is a hotspot because it is used by bsearch() to look up
metrics in a metric family. This simple (though non-obvious) change
brings prom_write() complexity down from 3000 instructions/call to 2640
instructions/call, i.e. a 12% improvement.

src/write_prometheus.c

index 4a9761a..6c88278 100644 (file)
@@ -297,17 +297,37 @@ static int metric_cmp(void const *a, void const *b) {
     return 1;
 
   /* Prometheus does not care about the order of labels. All labels in this
-   * plugin are created by metric_add_labels(), though, and therefore always
+   * plugin are created by METRIC_ADD_LABELS(), though, and therefore always
    * appear in the same order. We take advantage of this and simplify the check
-   * by making sure all labels are the same in each position. */
+   * by making sure all labels are the same in each position.
+   *
+   * We also only need to check the label values, because the label names are
+   * the same for all metrics in a metric family.
+   *
+   * 3 labels:
+   * [0] $plugin="$plugin_instance" => $plugin is the same within a family
+   * [1] type="$type_instance"      => "type" is a static string
+   * [2] instance="$host"           => "instance" is a static string
+   *
+   * 2 labels, variant 1:
+   * [0] $plugin="$plugin_instance" => $plugin is the same within a family
+   * [1] instance="$host"           => "instance" is a static string
+   *
+   * 2 labels, variant 2:
+   * [0] $plugin="$type_instance"   => $plugin is the same within a family
+   * [1] instance="$host"           => "instance" is a static string
+   *
+   * 1 label:
+   * [1] instance="$host"           => "instance" is a static string
+   */
   for (size_t i = 0; i < m_a->n_label; i++) {
-    int status = strcmp(m_a->label[i]->name, m_b->label[i]->name);
+    int status = strcmp(m_a->label[i]->value, m_b->label[i]->value);
     if (status != 0)
       return status;
 
-    status = strcmp(m_a->label[i]->value, m_b->label[i]->value);
-    if (status != 0)
-      return status;
+#if COLLECT_DEBUG
+    assert(strcmp(m_a->label[i]->name, m_b->label[i]->name) == 0);
+#endif
   }
 
   return 0;