Skip to content

Commit eb9d9ce

Browse files
authored
Add a chart to the web-site performance data (#567)
1 parent 11f261b commit eb9d9ce

File tree

6 files changed

+178
-7
lines changed

6 files changed

+178
-7
lines changed

src/site/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/markdown/download.md.in
5454
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/markdown/development/build-cmake.md.in
5555
${CMAKE_CURRENT_BINARY_DIR}/markdown/development/build-cmake.md )
5656

57+
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/echarts.min.js
58+
${CMAKE_CURRENT_BINARY_DIR}/html/echarts.min.js
59+
COPYONLY
60+
)
61+
configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/generate_appending_a_log_message.js
62+
${CMAKE_CURRENT_BINARY_DIR}/html/generate_appending_a_log_message.js
63+
COPYONLY
64+
)
65+
5766
add_custom_target( doc_doxygen ALL
5867
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
5968
WORKING_DIRECTORY ${LOG4CXX_SOURCE_DIR}

src/site/echarts.min.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
2+
// Get the DOM container for the plot
3+
var containerDOM = document.getElementById('appending_a_log_message_plot');
4+
if (!containerDOM) {
5+
throw new Error("Could not find 'appending_a_log_message_plot' element");
6+
}
7+
var myChart = echarts.init(containerDOM, null, { renderer: 'canvas' });
8+
9+
10+
// Find the benchmark html table
11+
var benchmark_data = null;
12+
var element = document.getElementById('benchmark_data_marker');
13+
while (element && element.tagName) {
14+
if (element.tagName === 'TABLE') {
15+
benchmark_data = element;
16+
break;
17+
}
18+
element = element.nextElementSibling;
19+
}
20+
if (!benchmark_data) {
21+
throw new Error("Could not find benchmark data");;
22+
}
23+
24+
// Identify the benchmark tests to be included on the plot
25+
var benchmark_pattern = [];
26+
benchmark_pattern.push(new RegExp("Appending (.*) using ([A-Za-z]+), pattern: \\%m\\%n$"));
27+
benchmark_pattern.push(new RegExp("Async, Sending (.*) using ([A-Za-z <]+)$"));
28+
const value_regex_pattern = new RegExp("([0-9]+) ns")
29+
30+
// Extract the data
31+
var plot_data = new Map();
32+
var xAxisLabels = [];
33+
for (const row of benchmark_data.rows) {
34+
const columns = row.cells;
35+
if (2 < columns.length) {
36+
const value_match = value_regex_pattern.exec(columns[1].innerText);
37+
if (value_match && 1 < value_match.length) {
38+
for (const pattern of benchmark_pattern) {
39+
const benchmark_match = pattern.exec(columns[0].innerText);
40+
if (benchmark_match && 2 < benchmark_match.length) {
41+
if (!xAxisLabels.includes(benchmark_match[1])) {
42+
xAxisLabels.push(benchmark_match[1]);
43+
}
44+
var keyValueMap = plot_data.get(benchmark_match[2]);
45+
if (!keyValueMap) {
46+
keyValueMap = new Map();
47+
plot_data.set(benchmark_match[2], keyValueMap);
48+
}
49+
keyValueMap.set(benchmark_match[1], value_match[1]);
50+
}
51+
}
52+
}
53+
}
54+
}
55+
56+
// Generate a series for each legend
57+
var legend_data = [];
58+
var series_data = [];
59+
for (const [key, keyValueMap] of plot_data.entries()) {
60+
legend_data.push(key);
61+
var series_values = [];
62+
for (const label of xAxisLabels) {
63+
var value = keyValueMap.get(label);
64+
series_values.push(value ? parseInt(value) : null);
65+
}
66+
var series_data_item = {
67+
name: key,
68+
type: 'line',
69+
data: series_values
70+
};
71+
series_data.push(series_data_item);
72+
}
73+
74+
// Configure the chart
75+
var chart_data = {
76+
title: { text: 'Appending a log message' },
77+
yAxis: {
78+
name: 'Average elapsed time (ns)',
79+
nameLocation: 'center'
80+
},
81+
legend: {
82+
orient: 'vertical',
83+
left: 150,
84+
top: 'center',
85+
data: legend_data
86+
},
87+
xAxis: {
88+
axisTick: { alignWithLabel: true },
89+
axisLabel: { rotate: 30 },
90+
name: 'Log message content',
91+
nameLocation: 'center',
92+
data: xAxisLabels
93+
},
94+
series: series_data
95+
};
96+
97+
// Display the chart
98+
myChart.setOption(chart_data);

src/site/markdown/performance.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ The "Iterations" column derivation is explained in [Google Benchmark documentati
8484
L2 Unified 256 KiB (x4)
8585
L3 Unified 6144 KiB (x1)
8686
Load Average: 0.07, 0.03, 0.01
87-
87+
@htmlonly
88+
<div id="benchmark_data_marker"></div>
89+
@endhtmlonly
8890
| Benchmark | Time | CPU | Iterations |
8991
| --------- | -------: | --: | ---------: |
9092
| Testing disabled logging request | 0.472 ns | 0.472 ns | 1000000000 |
@@ -123,20 +125,30 @@ The "Iterations" column derivation is explained in [Google Benchmark documentati
123125
-# The "Async" benchmarks test [AsyncAppender](@ref log4cxx::AsyncAppender) throughput, with logging events discarded in the background thread.
124126
-# The "Logging" benchmarks write to a file using buffered output. Overhead is 2-3 times more when not using buffered output.
125127

126-
The above table shows that the overhead of an enabled logging request
127-
varies greatly with the message content.
128-
A single operations-per-second number is not meaningful.
129-
Most importantly note that [using buffered output](@ref log4cxx::FileAppender::setOption)
130-
reduces overhead more than any other detail.
128+
@htmlonly
129+
<div id="appending_a_log_message_plot" style="width: 800px;height:400px;"></div>
130+
<script src="echarts.min.js"></script>
131+
<script src="generate_appending_a_log_message.js"></script>
132+
@endhtmlonly
133+
134+
The above graph shows that the overhead of an enabled logging request
135+
varies greatly with the message content and that
136+
the `LOG4CXX_[level]_FMT` macros have lower overhead.
137+
It also shows two data points where binary to text conversion
138+
is moved to a background thread
139+
using [AsyncBuffer](@ref log4cxx::helpers::AsyncBuffer) and [AsyncAppender](@ref log4cxx::AsyncAppender).
131140

132-
Note also that logging from multiple threads concurrently
141+
Note that logging from multiple threads concurrently
133142
to a common appender generally does not increase throughput
134143
due to lock contention in [doAppend method](@ref log4cxx::AppenderSkeleton::doAppend).
135144
To simplify the work of an appender implementator,
136145
the [doAppend method](@ref log4cxx::AppenderSkeleton::doAppend) currently prevents multiple threads
137146
concurrently entering [the append method](@ref log4cxx::AppenderSkeleton::append),
138147
which is the method required to be implemented by a concrete appender class.
139148

149+
Note also that [using buffered output](@ref log4cxx::FileAppender::setOption)
150+
reduces overhead more than any other detail.
151+
140152
The [AsyncAppender](@ref log4cxx::AsyncAppender) provides the least overhead
141153
when logging concurrently from multiple threads
142154
as it overrides the [doAppend method](@ref log4cxx::AsyncAppender::doAppend)

src/site/test_echarts.html

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8" />
5+
</head>
6+
<body>
7+
<h1>Test page for iterating through echarts format options</h1>
8+
<div id="appending_a_log_message_plot" style="width: 800px;height:400px;"></div>
9+
<script src="echarts.min.js"></script>
10+
<script src="test_echarts.js"></script>
11+
</body>
12+
<footer>
13+
14+
</footer>
15+
</html>

src/site/test_echarts.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
var chart_data = {
2+
"title": { "text": "Appending a log message" },
3+
"legend": {
4+
"orient": "vertical",
5+
"left": 150,
6+
"top": "center",
7+
"data": [ "MessageBuffer", "FMT", "FMT and AsyncBuffer", "operator<< and AsyncBuffer" ]
8+
},
9+
"xAxis": {
10+
axisTick: {
11+
alignWithLabel: true
12+
},
13+
axisLabel: {
14+
rotate: 30
15+
},
16+
name : 'Log message content',
17+
nameLocation : 'center',
18+
data : [ "5 char string", "49 char string", "int value", "int+float", "int+10float" ]
19+
},
20+
"yAxis": {
21+
name : 'Average elapsed time (ns)',
22+
nameLocation : 'center'
23+
},
24+
"series": [
25+
{ "type": "line", "name": "MessageBuffer", "data": [ 334, 370, 509, 911, 4579 ] },
26+
{ "type": "line", "name": "FMT", "data": [ null, 346, 376, 508, 1671 ] },
27+
{ "type": "line", "name": "FMT and AsyncBuffer", "data": [ null, null, null, null, 784 ] },
28+
{ "type": "line", "name": "operator<< and AsyncBuffer", "data": [ null, null, null, null, 1211 ] }
29+
]
30+
};
31+
32+
var containerDOM = document.getElementById('appending_a_log_message_plot');
33+
if (containerDOM) {
34+
var myChart = echarts.init(containerDOM, null, { renderer: 'canvas' });
35+
myChart.setOption(chart_data);
36+
}

0 commit comments

Comments
 (0)