FEATURE: add basic support for benchmark topics

FEATURE: add basic support for benchmark topics

Automatically creates charts for easy data comparison

diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 1f5eac0..b124115 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -3,3 +3,4 @@ en:
     dev_additions_enabled: "Allow dev additions"
     dev_additions_logs_topic_id: "The topic used for bug crushing game"
     dev_additions_logs_topic_group: "The group used for bug crushing game"
+    dev_additions_benchmark_topic_ids: "Comma seperated list of ids denoting benchmark topics"
diff --git a/config/settings.yml b/config/settings.yml
index b985922..c440e73 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -4,6 +4,7 @@ plugins:
     client: true
   dev_additions_logs_topic_id:
     default: 0
+  dev_additions_benchmark_topic_ids: ""
   dev_additions_logs_topic_group:
     type: group
     default: ""
diff --git a/plugin.rb b/plugin.rb
index ecf237c..926737a 100644
--- a/plugin.rb
+++ b/plugin.rb
@@ -33,4 +33,93 @@ after_initialize do
       public_admission: true,
     )
   end
+
+  def refresh_bench_topic(post)
+    return if post.post_number == 1
+    return if !SiteSetting.dev_additions_benchmark_topic_ids.split(",").include?(post.topic_id.to_s)
+
+    data = Post.where('topic_id = ? AND post_number > 1', post.topic_id).pluck(:raw, :post_number)
+
+    benches = {}
+
+    data.each do |(raw, post_number)|
+      desc = nil
+      bench_parsed = nil
+
+      raw.each_line do |line|
+        desc = line.strip if !desc && line.present?
+
+        if line.include? "on 1 core"
+          bench_parsed = :single
+        elsif line.match?(/on \d+ core/)
+          bench_parsed = :multi
+        elsif bench_parsed
+          match = line.match(/(.*): (\S+).*(op\/s|seconds)$/)
+          if match
+            name = match[1]
+            duration = match[2].to_f
+            durations = (benches["#{name}#{" (mp)" if bench_parsed == :multi}"] ||= [])
+            durations << {
+              duration: duration,
+              type: match[3] == "seconds" ? :secs : :ops,
+              post_number: post_number,
+              description: desc
+            }
+          end
+        end
+
+      end
+    end
+
+    markdown = +""
+
+    benches.each do |name, metrics|
+      type = metrics[0][:type] == :ops ? "op/s (higher is better)" : "seconds (lower is better)"
+
+      markdown << <<~MD
+        [chart borderColors="#f45,#c83,#d76" title="#{name.gsub('"', "")}" type="horizontalBar" xAxisTitle="#{type}" backgroundColors="#4cc"]
+      MD
+
+      metrics.sort! do |a, b|
+        if a[:type] == :ops
+          b[:duration] <=> a[:duration]
+        else
+          a[:duration] <=> b[:duration]
+        end
+      end
+
+      metrics.each do |row|
+        markdown << <<~MD
+          #{row[:description]} | #{row[:duration]}
+        MD
+      end
+
+      markdown << "[/chart]\n"
+    end
+
+    op = Post.find_by(topic_id: post.topic_id, post_number: 1)
+    raw = op.raw.split("<!--AUTO-->", 3)
+    raw[1] = markdown
+    raw[2] ||= ""
+
+    revisor = PostRevisor.new(op)
+    new_raw = +"" << raw[0]
+    new_raw << "\n" if new_raw[-1] != "\n"
+    new_raw << "<!--AUTO-->\n"
+    new_raw << markdown
+    new_raw << "<!--AUTO-->"
+    if raw[2]
+      new_raw << "\n" if raw[0] != "\n"
+      new_raw << raw[2]
+    end
+    revisor.revise!(Discourse.system_user, raw: new_raw)
+  end
+
+  DiscourseEvent.on(:post_edited) do |post|
+    refresh_bench_topic(post)
+  end
+
+  DiscourseEvent.on(:post_created) do |post|
+    refresh_bench_topic(post)
+  end
 end
diff --git a/spec/benchmark_spec.rb b/spec/benchmark_spec.rb
new file mode 100644
index 0000000..a94379e
--- /dev/null
+++ b/spec/benchmark_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+require 'rails_helper'
+
+describe "Benchmark topics" do
+
+  it "can extract benchmarks from posts" do
+    op = Fabricate(:post, raw: "My Awesome benchmarks...")
+
+    SiteSetting.dev_additions_benchmark_topic_ids = op.topic_id.to_s
+
+    bench = <<~BENCH
+      Sam's laptop
+
+      `‍``
+      Running benchmark on 1 core
+      --------------------
+
+      Topic View: 6.886 (±14.2%) op/s
+      Topic Create: 3.548 (±26.8%) op/s
+      ABC: 7.548 (±26.8%) seconds
+
+      `‍``
+    BENCH
+
+    bench2 = <<~BENCH
+      Sam's 2nd laptop
+
+      `‍``
+      Running benchmark on 1 core
+      --------------------
+
+      Topic View: 7.886 (±14.2%) op/s
+      Topic Create: 2.548 (±26.8%) op/s
+
+      `‍``
+    BENCH
+
+    bench1 = create_post(topic_id: op.topic_id, raw: bench)
+    bench2 = create_post(topic_id: op.topic_id, raw: bench2)
+
+    op.reload
+
+    expect(op.raw).to include("chart")
+
+  end
+end

GitHub sha: 1f32ec92

1 Like