This is an automated email from the ASF dual-hosted git repository.

swebb2066 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/logging-log4cxx.git


The following commit(s) were added to refs/heads/master by this push:
     new eb9d9ced Add a chart to the web-site performance data (#567)
eb9d9ced is described below

commit eb9d9ceddf007f1b0a91fe188d50af1cec6dcbbe
Author: Stephen Webb <[email protected]>
AuthorDate: Mon Dec 1 14:12:19 2025 +1100

    Add a chart to the web-site performance data (#567)
---
 src/site/CMakeLists.txt                      |  9 +++
 src/site/echarts.min.js                      |  1 +
 src/site/generate_appending_a_log_message.js | 98 ++++++++++++++++++++++++++++
 src/site/markdown/performance.md             | 26 ++++++--
 src/site/test_echarts.html                   | 15 +++++
 src/site/test_echarts.js                     | 36 ++++++++++
 6 files changed, 178 insertions(+), 7 deletions(-)

diff --git a/src/site/CMakeLists.txt b/src/site/CMakeLists.txt
index 25aef6bb..a2773243 100644
--- a/src/site/CMakeLists.txt
+++ b/src/site/CMakeLists.txt
@@ -54,6 +54,15 @@ configure_file( 
${CMAKE_CURRENT_SOURCE_DIR}/markdown/download.md.in
 configure_file( 
${CMAKE_CURRENT_SOURCE_DIR}/markdown/development/build-cmake.md.in
     ${CMAKE_CURRENT_BINARY_DIR}/markdown/development/build-cmake.md )
 
+configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/echarts.min.js
+    ${CMAKE_CURRENT_BINARY_DIR}/html/echarts.min.js
+    COPYONLY
+)
+configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/generate_appending_a_log_message.js
+    ${CMAKE_CURRENT_BINARY_DIR}/html/generate_appending_a_log_message.js
+    COPYONLY
+)
+
 add_custom_target( doc_doxygen ALL
     COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
     WORKING_DIRECTORY ${LOG4CXX_SOURCE_DIR}
diff --git a/src/site/echarts.min.js b/src/site/echarts.min.js
new file mode 100644
index 00000000..43e4952d
--- /dev/null
+++ b/src/site/echarts.min.js
@@ -0,0 +1 @@
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof 
module?e(exports):"function"==typeof 
define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof 
globalThis?globalThis:t||self).echarts={})}(this,function(t){"use strict";var 
_=function(t,e){return(_=Object.setPrototypeOf||({__proto__:[]}instanceof 
Array?function(t,e){t.__proto__=e}:function(t,e){for(var n in 
e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])}))(t,e)};function 
u(t,e){if("function"!=typeof e&&null!== [...]
\ No newline at end of file
diff --git a/src/site/generate_appending_a_log_message.js 
b/src/site/generate_appending_a_log_message.js
new file mode 100644
index 00000000..b57fba60
--- /dev/null
+++ b/src/site/generate_appending_a_log_message.js
@@ -0,0 +1,98 @@
+
+// Get the DOM container for the plot
+var containerDOM = document.getElementById('appending_a_log_message_plot');
+if (!containerDOM) {
+       throw new Error("Could not find 'appending_a_log_message_plot' 
element");
+}
+var myChart = echarts.init(containerDOM, null, { renderer: 'canvas' });
+
+
+// Find the benchmark html table
+var benchmark_data = null;
+var element = document.getElementById('benchmark_data_marker');
+while (element && element.tagName) {
+       if (element.tagName === 'TABLE') {
+               benchmark_data = element;
+               break;
+       }
+       element = element.nextElementSibling;
+}
+if (!benchmark_data) {
+       throw new Error("Could not find benchmark data");;
+}
+
+// Identify the benchmark tests to be included on the plot
+var benchmark_pattern = [];
+benchmark_pattern.push(new RegExp("Appending (.*) using ([A-Za-z]+), pattern: 
\\%m\\%n$"));
+benchmark_pattern.push(new RegExp("Async, Sending (.*) using ([A-Za-z <]+)$"));
+const value_regex_pattern = new RegExp("([0-9]+) ns")
+
+// Extract the data
+var plot_data = new Map();
+var xAxisLabels = [];
+for (const row of benchmark_data.rows) {
+       const columns = row.cells;
+       if (2 < columns.length) {
+               const value_match = 
value_regex_pattern.exec(columns[1].innerText);
+               if (value_match && 1 < value_match.length) {
+                       for (const pattern of benchmark_pattern) {
+                               const benchmark_match = 
pattern.exec(columns[0].innerText);
+                               if (benchmark_match && 2 < 
benchmark_match.length) {
+                                       if 
(!xAxisLabels.includes(benchmark_match[1])) {
+                                               
xAxisLabels.push(benchmark_match[1]);
+                                       }
+                                       var keyValueMap = 
plot_data.get(benchmark_match[2]);
+                                       if (!keyValueMap) {
+                                               keyValueMap = new Map();
+                                               
plot_data.set(benchmark_match[2], keyValueMap);
+                                       }
+                                       keyValueMap.set(benchmark_match[1], 
value_match[1]);
+                               }
+                       }
+               }
+       }
+}
+
+// Generate a series for each legend
+var legend_data = [];
+var series_data = [];
+for (const [key, keyValueMap] of plot_data.entries()) {
+       legend_data.push(key);
+       var series_values = [];
+       for (const label of xAxisLabels) {
+               var value = keyValueMap.get(label);
+               series_values.push(value ? parseInt(value) : null);
+       }
+       var series_data_item = {
+               name: key,
+               type: 'line',
+               data: series_values
+       };
+       series_data.push(series_data_item);
+}
+
+// Configure the chart
+var chart_data = {
+       title: { text: 'Appending a log message' },
+       yAxis: {
+               name: 'Average elapsed time (ns)',
+               nameLocation: 'center'
+       },
+       legend: { 
+               orient: 'vertical',
+               left: 150,
+               top: 'center',
+               data: legend_data
+        },
+       xAxis: {
+               axisTick: { alignWithLabel: true },
+               axisLabel: { rotate: 30 },
+               name: 'Log message content',
+               nameLocation: 'center',
+               data: xAxisLabels
+       },
+       series: series_data
+};
+
+// Display the chart
+myChart.setOption(chart_data);
diff --git a/src/site/markdown/performance.md b/src/site/markdown/performance.md
index 2cefd64d..6fd2254d 100644
--- a/src/site/markdown/performance.md
+++ b/src/site/markdown/performance.md
@@ -84,7 +84,9 @@ The "Iterations" column derivation is explained in [Google 
Benchmark documentati
          L2 Unified 256 KiB (x4)
          L3 Unified 6144 KiB (x1)
        Load Average: 0.07, 0.03, 0.01
-
+@htmlonly
+<div id="benchmark_data_marker"></div>
+@endhtmlonly
 | Benchmark |     Time | CPU | Iterations |
 | --------- | -------: | --: | ---------: |
 | Testing disabled logging request | 0.472 ns | 0.472 ns | 1000000000 |
@@ -123,13 +125,20 @@ The "Iterations" column derivation is explained in 
[Google Benchmark documentati
 -# The "Async" benchmarks test [AsyncAppender](@ref log4cxx::AsyncAppender) 
throughput, with logging events discarded in the background thread.
 -# The "Logging" benchmarks write to a file using buffered output. Overhead is 
2-3 times more when not using buffered output.
 
-The above table shows that the overhead of an enabled logging request
-varies greatly with the message content.
-A single operations-per-second number is not meaningful.
-Most importantly note that [using buffered output](@ref 
log4cxx::FileAppender::setOption)
-reduces overhead more than any other detail.
+@htmlonly
+<div id="appending_a_log_message_plot" style="width: 
800px;height:400px;"></div>
+<script src="echarts.min.js"></script>
+<script src="generate_appending_a_log_message.js"></script>
+@endhtmlonly
+
+The above graph shows that the overhead of an enabled logging request
+varies greatly with the message content and that
+the `LOG4CXX_[level]_FMT` macros have lower overhead.
+It also shows two data points where binary to text conversion
+is moved to a background thread
+using [AsyncBuffer](@ref log4cxx::helpers::AsyncBuffer) and 
[AsyncAppender](@ref log4cxx::AsyncAppender).
 
-Note also that logging from multiple threads concurrently
+Note that logging from multiple threads concurrently
 to a common appender generally does not increase throughput
 due to lock contention in [doAppend method](@ref 
log4cxx::AppenderSkeleton::doAppend).
 To simplify the work of an appender implementator,
@@ -137,6 +146,9 @@ the [doAppend method](@ref 
log4cxx::AppenderSkeleton::doAppend) currently preven
 concurrently entering [the append method](@ref 
log4cxx::AppenderSkeleton::append),
 which is the method required to be implemented by a concrete appender class.
 
+Note also that [using buffered output](@ref log4cxx::FileAppender::setOption)
+reduces overhead more than any other detail.
+
 The [AsyncAppender](@ref log4cxx::AsyncAppender) provides the least overhead
 when logging concurrently from multiple threads
 as it overrides the [doAppend method](@ref log4cxx::AsyncAppender::doAppend)
diff --git a/src/site/test_echarts.html b/src/site/test_echarts.html
new file mode 100644
index 00000000..2c556804
--- /dev/null
+++ b/src/site/test_echarts.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8" />
+  </head>
+  <body>
+  <h1>Test page for iterating through echarts format options</h1>
+  <div id="appending_a_log_message_plot" style="width: 
800px;height:400px;"></div>
+  <script src="echarts.min.js"></script>
+  <script src="test_echarts.js"></script>
+  </body>
+  <footer>
+
+  </footer>
+</html>
\ No newline at end of file
diff --git a/src/site/test_echarts.js b/src/site/test_echarts.js
new file mode 100644
index 00000000..f9da1149
--- /dev/null
+++ b/src/site/test_echarts.js
@@ -0,0 +1,36 @@
+var chart_data = {
+       "title": { "text": "Appending a log message" },
+       "legend": {
+               "orient": "vertical",
+               "left": 150,
+               "top": "center",
+               "data": [ "MessageBuffer", "FMT", "FMT and AsyncBuffer", 
"operator<< and AsyncBuffer" ]
+       },
+       "xAxis": {
+               axisTick: {
+        alignWithLabel: true
+      },
+      axisLabel: {
+        rotate: 30
+      },
+               name : 'Log message content',
+               nameLocation : 'center',
+               data : [ "5 char string", "49 char string", "int value", 
"int+float", "int+10float" ]
+       },
+       "yAxis": {
+               name : 'Average elapsed time (ns)',
+               nameLocation : 'center'
+               },
+       "series": [
+               { "type": "line", "name": "MessageBuffer",              "data": 
[ 334, 370, 509, 911, 4579 ] },
+               { "type": "line", "name": "FMT",                        "data": 
[ null, 346, 376, 508, 1671 ] },
+               { "type": "line", "name": "FMT and AsyncBuffer",        "data": 
[ null, null, null, null, 784 ] },
+               { "type": "line", "name": "operator<< and AsyncBuffer", "data": 
[ null, null, null, null, 1211 ] }
+       ]
+};
+
+var containerDOM = document.getElementById('appending_a_log_message_plot');
+if (containerDOM) {
+       var myChart = echarts.init(containerDOM, null, { renderer: 'canvas' });
+       myChart.setOption(chart_data);
+}

Reply via email to