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);
+}