This is an automated email from the ASF dual-hosted git repository.
liujun pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/dubbo-website.git
The following commit(s) were added to refs/heads/master by this push:
new 32b696dfe02 Feature: add manual benchmark test running (#2971)
32b696dfe02 is described below
commit 32b696dfe02797ca707b319aa9dea835e9417385
Author: wxbty <[email protected]>
AuthorDate: Fri May 10 16:37:27 2024 +0800
Feature: add manual benchmark test running (#2971)
---
.github/workflows/build_and_deploy.yml | 10 +
.gitignore | 6 +
benchmark/babel.config.js | 5 +
benchmark/jsconfig.json | 19 +
benchmark/package.json | 49 ++
benchmark/public/index.html | 17 +
benchmark/src/App.vue | 42 ++
benchmark/src/components/TriggerTraceDetail.vue | 703 +++++++++++++++++++++
benchmark/src/main.js | 16 +
benchmark/vue.config.js | 5 +
build_bh.sh | 21 +
.../performance/page-benchmarking.md | 26 +
package.json | 6 +-
static/fonts/element-icons.f1a45d74.ttf | Bin 0 -> 55956 bytes
static/fonts/element-icons.ff18efd1.woff | Bin 0 -> 28200 bytes
15 files changed, 922 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/build_and_deploy.yml
b/.github/workflows/build_and_deploy.yml
index 5e68d8ee107..0d98847e93f 100644
--- a/.github/workflows/build_and_deploy.yml
+++ b/.github/workflows/build_and_deploy.yml
@@ -75,3 +75,13 @@ jobs:
publish_branch: cn-site
publish_dir: ./public
keep_files: true
+ - name: Build Benchmark
+ run: sh ./build_bh.sh
+ - name: Deploy Benchmark
+ uses: peaceiris/actions-gh-pages@v3
+ if: github.ref == 'refs/heads/master'
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ publish_branch: cn-site
+ publish_dir: ./static
+ keep_files: true
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 0a4ea499b46..765e8cdf6e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,9 @@ package-lock.json
.DS_Store
/.hugo_build.lock
+benchmark/dist/
+static/css/app.css
+static/css/chunk-vendors.css
+static/js/app.js
+static/js/chunk-vendors.js
+
diff --git a/benchmark/babel.config.js b/benchmark/babel.config.js
new file mode 100644
index 00000000000..e9558405fdc
--- /dev/null
+++ b/benchmark/babel.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+ presets: [
+ '@vue/cli-plugin-babel/preset'
+ ]
+}
diff --git a/benchmark/jsconfig.json b/benchmark/jsconfig.json
new file mode 100644
index 00000000000..4aafc5f6ed8
--- /dev/null
+++ b/benchmark/jsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "esnext",
+ "baseUrl": "./",
+ "moduleResolution": "node",
+ "paths": {
+ "@/*": [
+ "src/*"
+ ]
+ },
+ "lib": [
+ "esnext",
+ "dom",
+ "dom.iterable",
+ "scripthost"
+ ]
+ }
+}
diff --git a/benchmark/package.json b/benchmark/package.json
new file mode 100644
index 00000000000..be3ada62de8
--- /dev/null
+++ b/benchmark/package.json
@@ -0,0 +1,49 @@
+{
+ "name": "dubbo-benchmark",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "serve": "vue-cli-service serve",
+ "build": "vue-cli-service build",
+ "lint": "vue-cli-service lint"
+ },
+ "dependencies": {
+ "@vue/cli": "^5.0.8",
+ "core-js": "^3.8.3",
+ "echarts": "^5.5.0",
+ "element-ui": "^2.13.2",
+ "jquery": "^3.7.1",
+ "vue": "^2.6.14",
+ "vue-router": "^3.6.5",
+ "zrender": "^5.5.0"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.12.16",
+ "@babel/eslint-parser": "^7.12.16",
+ "@vue/cli-plugin-babel": "~5.0.0",
+ "@vue/cli-plugin-eslint": "~5.0.0",
+ "@vue/cli-service": "~5.0.0",
+ "eslint": "^7.32.0",
+ "eslint-plugin-vue": "^8.0.3",
+ "vue-template-compiler": "^2.6.14"
+ },
+ "eslintConfig": {
+ "root": true,
+ "env": {
+ "node": true
+ },
+ "extends": [
+ "plugin:vue/essential",
+ "eslint:recommended"
+ ],
+ "parserOptions": {
+ "parser": "@babel/eslint-parser"
+ },
+ "rules": {}
+ },
+ "browserslist": [
+ "> 1%",
+ "last 2 versions",
+ "not dead"
+ ]
+}
diff --git a/benchmark/public/index.html b/benchmark/public/index.html
new file mode 100644
index 00000000000..5b3eb170de0
--- /dev/null
+++ b/benchmark/public/index.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html lang="">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width,initial-scale=1.0">
+ <link rel="icon" href="<%= BASE_URL %>dubbo.png">
+ <title><%= htmlWebpackPlugin.options.title %></title>
+ </head>
+ <body>
+ <noscript>
+ <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't
work properly without JavaScript enabled. Please enable it to continue.</strong>
+ </noscript>
+ <div id="app"></div>
+ <!-- built files will be auto injected -->
+ </body>
+</html>
diff --git a/benchmark/src/App.vue b/benchmark/src/App.vue
new file mode 100644
index 00000000000..1557d63c2e7
--- /dev/null
+++ b/benchmark/src/App.vue
@@ -0,0 +1,42 @@
+<template>
+ <div id="app">
+ <el-row>
+ <el-col :span="24"><div style="font-size: 30px">Dubbo 基准测试</div></el-col>
+ </el-row>
+ <el-row>
+ <el-col :span="24"><div style="font-size: 15px; text-align: right;">
+ <a target="_blank"
+
href="https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories">
+ 32并发线程 Linux 4C8T 16GB JDK1.8</a>
+ </div>
+ </el-col>
+ </el-row>
+
+ <el-row style="margin-top: 100px">
+ <el-divider><span style="font-size: 20px;">手动触发对比</span></el-divider>
+ <el-col :span="24"><trigger-trace-detail></trigger-trace-detail></el-col>
+ </el-row>
+ </div>
+</template>
+
+<script>
+import TriggerTraceDetail from "@/components/TriggerTraceDetail.vue";
+
+export default {
+ name: 'App',
+ components: {
+ TriggerTraceDetail
+ }
+}
+</script>
+
+<style>
+#app {
+ font-family: Avenir, Helvetica, Arial, sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ text-align: center;
+ color: #2c3e50;
+ //margin-top: 60px;
+}
+</style>
diff --git a/benchmark/src/components/TriggerTraceDetail.vue
b/benchmark/src/components/TriggerTraceDetail.vue
new file mode 100644
index 00000000000..37df54acb7f
--- /dev/null
+++ b/benchmark/src/components/TriggerTraceDetail.vue
@@ -0,0 +1,703 @@
+<template>
+ <div>
+ <div class="form-layout">
+ <el-form label-width="100px" class="left-form">
+ <el-form-item label="仓库地址" prop="repo_url">
+ <el-input v-model="REPO_URL" placeholder="仓库地址"></el-input>
+ </el-form-item>
+
+ <el-form-item label="Github Token" prop="PUSH_TOKEN">
+ <el-input v-model="PUSH_TOKEN" placeholder="token"></el-input>
+ </el-form-item>
+
+ <!-- 使用一个新的form-item来包裹后三个需要放在一行的元素,但这样做并不是标准的。通常,form-item直接放在form下面
-->
+ <el-row :gutter="20" class="form-row">
+ <el-col :span="8">
+ <el-form-item label="左侧配置" prop="leftSelectedOptions"
class="form-item-in-row">
+ <el-cascader v-model="leftSelectedOptions"
:options="cascaderOptions" clearable></el-cascader>
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item label="右侧配置" prop="rightSelectedOptions"
class="form-item-in-row">
+ <el-cascader v-model="rightSelectedOptions"
:options="cascaderOptions" clearable></el-cascader>
+ </el-form-item>
+ </el-col>
+ <el-col :span="8">
+ <el-form-item class="form-item-in-row">
+ <el-button type="primary" @click="open">开始运行</el-button>
+ </el-form-item>
+ </el-col>
+ </el-row>
+ </el-form>
+ <div class="right-text">
+ <div
+ style="font-size: 16px; line-height: 1.5; border: 1px solid #ccc;
padding: 10px; margin-bottom: 20px; text-decoration: none; text-align: left;">
+ <p style="text-align: left;">用户需提供一个自己的GitHub仓库来存储数据,可以新创建一个,
+ 也可使用现有的。您只需要参照示例仓库(<a href="https://github.com/dyjjack/jmh_result"
target="_blank">jmh_result</a>可直接fork)
+ 的workflow的配置即可。此外,为确保有权限推送数据,还需配置用户的GitHub Token。</p>
+ </div>
+ </div>
+ </div>
+
+ <el-row>
+ <el-col :span="6">
+ <div id="TriggerP99" style="width:100%;height:400px;margin-top:
30px"></div>
+ </el-col>
+ <el-col :span="6">
+ <div id="TriggerQps" style="width:100%;height:400px;margin-top:
30px"></div>
+ </el-col>
+ <el-col :span="6">
+ <el-header>
+ <h1 style="overflow: hidden; white-space: nowrap; text-overflow:
ellipsis">{{ leftTableTitle }}</h1>
+ </el-header>
+ <el-table
+ :data="leftTableDate"
+ style="width: 100%"
+ row-key="spanId_"
+ border
+ lazy
+ default-expand-all
+ :tree-props="{children: 'children'}"
+ >
+ <el-table-column prop="operationName_" label="方法名"
min-width="82%"></el-table-column>
+ <el-table-column prop="cost" label="耗时(ms)"
min-width="18%"></el-table-column>
+ </el-table>
+ </el-col>
+
+ <el-col :span="6">
+ <el-header>
+ <h1>{{ rightTableTitle }}</h1>
+ </el-header>
+ <el-table
+ :data="rightTableDate"
+ style="width: 100%"
+ row-key="spanId_"
+ border
+ lazy
+ default-expand-all
+ :tree-props="{children: 'children'}"
+ >
+ <el-table-column prop="operationName_" label="方法名"
min-width="82%"></el-table-column>
+ <el-table-column prop="cost" label="耗时(ms)"
min-width="18%"></el-table-column>
+ </el-table>
+ </el-col>
+ </el-row>
+ </div>
+</template>
+
+<script>
+export default {
+ name: 'TriggerTraceDetail',
+ data() {
+ return {
+ REPO_URL: null,
+ PUSH_NAME: null,
+ REPO_NAME: null,
+ PUSH_TOKEN: null,
+
+ triggerTable: [],
+
+ leftTableTitle: '',
+ leftTableDate: [],
+ rightTableDate: [],
+ rightTableTitle: '',
+
+ leftSelectedOptions: [],
+ rightSelectedOptions: [],
+
+ resultList: [],
+
+ cascaderOptions: [{
+ value: 'dubbo',
+ label: 'Dubbo协议',
+ children: [{
+ value: 'hessian2',
+ label: 'Hessian2'
+ }, {
+ value: 'fastjson2',
+ label: 'Fastjson2'
+ }, {
+ value: 'fastjson',
+ label: 'Fastjson'
+ }, {
+ value: 'avro',
+ label: 'Avro'
+ }, {
+ value: 'fst',
+ label: 'Fst'
+ }, {
+ value: 'gson',
+ label: 'Gson'
+ }, {
+ value: 'kryo',
+ label: 'Kryo'
+ }, {
+ value: 'msgpack',
+ label: 'Msgpack'
+ }]
+ }, {
+ value: 'rmi',
+ label: 'Rmi协议',
+ children: [{
+ value: 'hessian2',
+ label: 'Hessian2'
+ }, {
+ value: 'fastjson2',
+ label: 'Fastjson2'
+ }, {
+ value: 'fastjson',
+ label: 'Fastjson'
+ }, {
+ value: 'avro',
+ label: 'Avro'
+ }, {
+ value: 'fst',
+ label: 'Fst'
+ }, {
+ value: 'gson',
+ label: 'Gson'
+ }, {
+ value: 'kryo',
+ label: 'Kryo'
+ }, {
+ value: 'msgpack',
+ label: 'Msgpack'
+ }]
+ }, {
+ value: 'tri',
+ label: 'Triple协议',
+ children: [{
+ value: 'hessian2',
+ label: 'Hessian2'
+ }, {
+ value: 'fastjson2',
+ label: 'Fastjson2'
+ }, {
+ value: 'fastjson',
+ label: 'Fastjson'
+ }, {
+ value: 'avro',
+ label: 'Avro'
+ }, {
+ value: 'fst',
+ label: 'Fst'
+ }, {
+ value: 'gson',
+ label: 'Gson'
+ }, {
+ value: 'kryo',
+ label: 'Kryo'
+ }, {
+ value: 'msgpack',
+ label: 'Msgpack'
+ }]
+ }],
+ };
+ },
+
+ mounted() {
+ try {
+ this.init();
+ this.sampleEcharts();
+ this.thrptEcharts();
+ } catch (error) {
+ console.error("init:", error);
+ }
+ try {
+ this.initTable();
+ } catch (error) {
+ console.error("initTable:", error);
+ }
+ },
+
+ methods: {
+ init() {
+ this.REPO_URL = localStorage.getItem('REPO_URL') || ''
+ this.PUSH_NAME = localStorage.getItem('PUSH_NAME') || ''
+ this.REPO_NAME = localStorage.getItem('REPO_NAME') || ''
+ this.PUSH_TOKEN = localStorage.getItem('PUSH_TOKEN') || ''
+
+
+ if (this.PUSH_NAME && this.REPO_NAME) {
+ let jmh;
+
+ const gitUrlPattern =
/^https:\/\/github\.com\/([^/]+)\/([^/]+)\.git$/; // 正则表达式匹配带.git后缀的GitHub仓库URL
+ const match = this.REPO_URL.match(gitUrlPattern);
+ if (match) {
+ this.PUSH_NAME = match[1]; // 用户名是第一个捕获组
+ this.REPO_NAME = match[2]; // 仓库名是第二个捕获组
+ }
+
+ this.$.ajax({
+ type: "GET",
+ async: false,
+ url: "https://raw.githubusercontent.com/" + this.PUSH_NAME + "/" +
this.REPO_NAME + "/main/test-results/scenario/merged_prop_results.json",
+ success: function (res) {
+ jmh = res
+ }
+ });
+
+ try {
+ this.resultList = JSON.parse(jmh);
+ } catch (error) {
+ console.error("解析JMH结果字符串出错:", error);
+ throw error;
+ }
+ }
+ },
+
+ sampleEcharts() {
+ // 基于准备好的dom,初始化echarts实例
+ const myChart =
this.$echarts.init(document.getElementById('TriggerP99'));
+
+ let time = this.resultList[0].params.time
+// 转换数据结构,按serialization属性分类并收集Item对象
+ let collect = this.resultList
+ .filter((a) => a.mode === 'sample')
+ .map((result) => {
+ // 注意这里只用一个参数接收当前元素
+ let protocol =
JSON.parse(result.params.prop)['dubbo.protocol.name'];
+ let serialization =
JSON.parse(result.params.prop)['dubbo.protocol.serialization']
+ return {
+ score: Number((result.primaryMetric.scorePercentiles['99.0'] *
1000).toFixed(1)),
+ protocol: protocol + "-" + serialization
+ };
+ });
+
+ // let seriesDate = collect.map((result) => {
+ // // 注意这里只用一个参数接收当前元素
+ // return {
+ // type: 'bar'
+ // };
+ // });
+ //
+ // console.log(collect);
+ // console.log(seriesDate);
+
+ let option = {
+ title: {
+ text: 'P99对比',
+ x: 'center',
+ subtext: this.timestampToTime(time)
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'none'
+ },
+ formatter: function (params) {
+ return params[0].data.score + 'ms';
+ }
+ },
+ toolbox: {
+ feature: {
+ saveAsImage: {}
+ }
+ },
+ grid: {
+ // top: '3%',
+ left: '3%',
+ right: '3%',
+ bottom: '3%',
+ containLabel: true
+ },
+ xAxis: {
+ type: 'category'
+ },
+ yAxis: {
+ type: 'value',
+ name: '耗时(ms)'
+ },
+ dataset: {
+ dimensions: ['protocol', 'score'],
+ source: collect
+ },
+ series: [
+ {
+ barWidth: '25%',
+ type: 'bar',
+ label: {
+ //柱体上显示数值
+ show: true, //开启显示
+ position: 'top', //在上方显示
+ textStyle: {
+ //数值样式
+ fontSize: '15px',
+ color: '#666'
+ },
+ }
+ }
+ ]
+ };
+
+ // 使用刚指定的配置项和数据显示图表。
+ myChart.setOption(option);
+ },
+
+ thrptEcharts() {
+ // 基于准备好的dom,初始化echarts实例
+ const myChart =
this.$echarts.init(document.getElementById('TriggerQps'));
+
+ let time = this.resultList[0].params.time
+// 转换数据结构,按serialization属性分类并收集Item对象
+ let collect = this.resultList
+ .filter((a) => a.mode === 'thrpt')
+ .map((result) => {
+ // 注意这里只用一个参数接收当前元素
+ let protocol =
JSON.parse(result.params.prop)['dubbo.protocol.name'];
+ let serialization =
JSON.parse(result.params.prop)['dubbo.protocol.serialization']
+ return {
+ score: Math.round(result.primaryMetric.scorePercentiles['99.0']),
+ protocol: protocol + "-" + serialization
+ };
+ });
+
+ // let seriesDate = collect.map((result) => {
+ // // 注意这里只用一个参数接收当前元素
+ // return {
+ // type: 'bar'
+ // };
+ // });
+ //
+ // console.log(collect);
+ // console.log(seriesDate);
+
+ let option = {
+ title: {
+ text: 'QPS对比',
+ x: 'center',
+ subtext: this.timestampToTime(time)
+ },
+ tooltip: {
+ trigger: 'axis',
+ axisPointer: {
+ type: 'none'
+ },
+ formatter: function (params) {
+ return params[0].data.score + 'ops/s';
+ }
+ },
+ toolbox: {
+ feature: {
+ saveAsImage: {}
+ }
+ },
+ grid: {
+ // top: '3%',
+ left: '3%',
+ right: '3%',
+ bottom: '3%',
+ containLabel: true
+ },
+ xAxis: {
+ type: 'category'
+ },
+ yAxis: {
+ type: 'value',
+ name: 'ops/s'
+ },
+ dataset: {
+ dimensions: ['protocol', 'score'],
+ source: collect
+ },
+ series: [
+ {
+ barWidth: '25%',
+ type: 'bar',
+ label: {
+ //柱体上显示数值
+ show: true, //开启显示
+ position: 'top', //在上方显示
+ textStyle: {
+ //数值样式
+ fontSize: '15px',
+ color: '#666'
+ },
+ }
+ }
+ ]
+ };
+
+ // 使用刚指定的配置项和数据显示图表。
+ myChart.setOption(option);
+ },
+
+ timestampToTime(timestamp) {
+ let date = new Date(Number(timestamp));
+ let Y = date.getFullYear() + '-';
+ let M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) :
date.getMonth() + 1) + '-';
+ let D = date.getDate() + ' ';
+ let h = date.getHours() + ':';
+ let m = date.getMinutes() + ':';
+ let s = date.getSeconds();
+
+ return Y + M + D + h + m + s;
+ },
+ initTable() {
+
+ if (this.PUSH_NAME && this.REPO_NAME) {
+ let jmh;
+
+ this.$.ajax({
+ type: "GET",
+ async: false,
+ url: "https://raw.githubusercontent.com/" + this.PUSH_NAME + "/" +
this.REPO_NAME + "/main/test-results/scenario/merged_prop_traces.json",
+ success: function (res) {
+ jmh = res
+ }
+ });
+
+ try {
+ this.triggerTable = JSON.parse(jmh);
+ } catch (error) {
+ console.error("解析JMH结果字符串出错:", error);
+ }
+
+ this.leftTableDate = this.createSpanTree(this.triggerTable != null &&
this.triggerTable.length > 0 ? this.triggerTable[0].spans_ : [])
+ this.rightTableDate = this.createSpanTree(this.triggerTable != null &&
this.triggerTable.length > 1 ? this.triggerTable[1].spans_ : [])
+
+ this.leftTableTitle = this.triggerTable != null &&
this.triggerTable.length > 0 ?
JSON.parse(this.triggerTable[0].prop)['dubbo.protocol.name'] + "-" +
JSON.parse(this.triggerTable[0].prop)['dubbo.protocol.serialization'] : ""
+ this.rightTableTitle = this.triggerTable != null &&
this.triggerTable.length > 1 ?
JSON.parse(this.triggerTable[1].prop)['dubbo.protocol.name'] + "-" +
JSON.parse(this.triggerTable[1].prop)['dubbo.protocol.serialization'] : ""
+ }
+
+ }
+ ,
+
+ createSpanTree(spans) {
+ console.log(spans)
+ let spanMap = new Map();
+ let rootSpans = [];
+
+ // 遍历原始spans,初始化每个span,创建映射表和寻找根span
+ for (let span of spans) {
+ spanMap.set(span.spanId_, {
+ ...span,
+ spanId_: span.spanId_.toString(),
+ cost: span.endTime_ - span.startTime_,
+ children: []
+ });
+ if (span.parentSpanId_ === -1) {
+ rootSpans.push(spanMap.get(span.spanId_));
+ }
+ }
+
+ // 根据 parentSpanId_ 属性构建树结构
+ for (let span of spans) {
+ if (span.parentSpanId_ !== -1) {
+ let parentSpan = spanMap.get(span.parentSpanId_);
+ if (parentSpan) {
+ parentSpan.children.push(spanMap.get(span.spanId_));
+ }
+ }
+ }
+
+ console.log(rootSpans)
+ return rootSpans;
+ },
+
+ open() {
+ if ((this.leftSelectedOptions == null || this.leftSelectedOptions.length
=== 0) && (this.rightSelectedOptions == null ||
this.rightSelectedOptions.length === 0)) {
+ this.$message({
+ type: 'warning',
+ message: '请选择至少一个'
+ });
+ return
+ }
+ if (!this.PUSH_TOKEN) {
+ this.$message({
+ type: 'warning',
+ message: 'token为空'
+ });
+ return
+ }
+ if (!this.REPO_URL) {
+ this.$message({
+ type: 'warning',
+ message: '仓库地址为空'
+ });
+ return
+ }
+
+ let leftRpc = null;
+ let leftSerialization = null;
+
+ console.log(this.leftSelectedOptions)
+ if (this.leftSelectedOptions.length > 0) {
+ leftRpc = this.leftSelectedOptions[0]
+ leftSerialization = this.leftSelectedOptions[1]
+ }
+
+ let rightRpc = null;
+ let rightSerialization = null;
+ if (this.rightSelectedOptions.length > 0) {
+ rightRpc = this.rightSelectedOptions[0]
+ rightSerialization = this.rightSelectedOptions[1]
+ }
+
+ const h = this.$createElement;
+
+ this.$msgbox({
+ title: '消息',
+ message: h('p', null, [
+ h('p', null, "左边内容:rpc协议:" + (leftRpc == null ? "" : leftRpc) +
"序列化:" + (leftSerialization == null ? "" : leftSerialization)),
+ h('p', null, "右边内容:rpc协议:" + (rightRpc == null ? "" : rightRpc) +
"序列化:" + (rightSerialization == null ? "" : rightSerialization)),
+ ]),
+ showCancelButton: true,
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ beforeClose: (action, instance, done) => {
+ if (action === 'confirm') {
+ let leftSendDate = ""
+ if (leftRpc) {
+ leftSendDate += "dubbo.protocol.name|" + leftRpc;
+ }
+ if (leftSerialization) {
+ if (leftRpc) {
+ leftSendDate += "|";
+ }
+ leftSendDate += "dubbo.protocol.serialization|" +
leftSerialization;
+ }
+
+ let rightSendDate = ""
+ if (rightRpc) {
+ rightSendDate += "dubbo.protocol.name|" + rightRpc;
+ }
+ if (rightSerialization) {
+ if (rightRpc) {
+ rightSendDate += "|";
+ }
+ rightSendDate += "dubbo.protocol.serialization|" +
rightSerialization;
+ }
+
+ let prop = leftSendDate + (leftSendDate ? "@" : "") +
rightSendDate;
+
+ instance.confirmButtonLoading = true;
+ instance.confirmButtonText = '执行中...';
+
+ const gitUrlPattern =
/^https:\/\/github\.com\/([^/]+)\/([^/]+)\.git$/; // 正则表达式匹配带.git后缀的GitHub仓库URL
+ const match = this.REPO_URL.match(gitUrlPattern);
+ if (match) {
+ this.PUSH_NAME = match[1]; // 用户名是第一个捕获组
+ this.REPO_NAME = match[2]; // 仓库名是第二个捕获组
+ } else {
+ this.PUSH_NAME = '';
+ this.REPO_NAME = '';
+ this.$message({
+ type: 'error',
+ message: '输入的URL格式不正确,请确保它是带有.git后缀的GitHub仓库URL'
+ });
+ }
+
+ this.$.ajax({
+ url: "https://api.github.com/repos/" + this.PUSH_NAME + "/" +
this.REPO_NAME + "/dispatches",
+ type: "POST",
+ beforeSend: (xhr) => {
+ xhr.setRequestHeader("Authorization", "Basic " +
btoa("username:" + this.PUSH_TOKEN));
+ xhr.setRequestHeader("Content-Type", "application/json");
+ xhr.setRequestHeader("Accept",
"application/vnd.github.everest-preview+json");
+ },
+ data: JSON.stringify({
+ "event_type": "manual-trigger",
+ "client_payload": {
+ "prop": prop,
+ "PUSH_NAME": this.PUSH_NAME,
+ "REPO_NAME": this.REPO_NAME,
+ "PUSH_TOKEN": this.PUSH_TOKEN,
+ "RESULTS_REPO_BRANCH": 'main'
+ }
+ }),
+
+ PUSH_NAME: null,
+ REPO_NAME: null,
+ PUSH_TOKEN: null,
+
+ success: (data) => {
+ instance.confirmButtonLoading = false;
+ console.log("Success:", data);
+ localStorage.setItem('PUSH_NAME', this.PUSH_NAME)
+ localStorage.setItem('REPO_NAME', this.REPO_NAME)
+ localStorage.setItem('PUSH_TOKEN', this.PUSH_TOKEN)
+ localStorage.setItem('REPO_URL', this.REPO_URL)
+ done();
+ },
+ error: (xhr, status, error) => {
+ instance.confirmButtonLoading = false;
+ console.error("Error:", error);
+ this.$message({
+ type: 'error',
+ message: '触发失败'
+ });
+ }
+ });
+ } else {
+ done();
+ }
+ }
+ }).then(() => {
+ this.$message({
+ type: 'success',
+ message: '触发成功!结果将在一小时内显示'
+ });
+ }).catch(() => {
+ this.$message({
+ type: 'info',
+ message: '已取消'
+ });
+ });
+ }
+ }
+}
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped>
+h3 {
+ margin: 40px 0 0;
+}
+
+ul {
+ list-style-type: none;
+ padding: 0;
+}
+
+li {
+ display: inline-block;
+ margin: 0 10px;
+}
+
+a {
+ color: #42b983;
+}
+
+.form-layout {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start; /* 根据需要调整垂直对齐方式 */
+}
+
+.left-form {
+ flex: 1; /* 占据剩余空间的一部分 */
+ max-width: calc(50% - 20px); /* 假设两边间隔为20px,则左侧表单最大宽度为50%减去间隔 */
+ margin-right: 20px; /* 右边距,与.right-text保持间隔 */
+}
+
+.right-text {
+ flex-shrink: 0; /* 防止.right-text被压缩 */
+ width: calc(50% - 20px); /* 右侧文本区域宽度 */
+ /* 其他样式,如字体大小、颜色等 */
+}
+
+.left-form .el-form-item__label {
+ text-align: left; /* 确保标签左对齐 */
+}
+
+.left-form .el-row {
+ display: flex; /* 使用Flexbox布局 */
+ align-items: center; /* 垂直居中 */
+}
+
+.left-form .el-col {
+ display: flex;
+ flex-direction: column; /* 子元素垂直排列 */
+}
+</style>
\ No newline at end of file
diff --git a/benchmark/src/main.js b/benchmark/src/main.js
new file mode 100644
index 00000000000..3e93f1615e7
--- /dev/null
+++ b/benchmark/src/main.js
@@ -0,0 +1,16 @@
+import Vue from 'vue'
+import App from './App.vue'
+import ElementUI from 'element-ui'
+import 'element-ui/lib/theme-chalk/index.css'
+import * as echarts from 'echarts';
+import $ from 'jquery'
+
+Vue.prototype.$=$
+Vue.prototype.$echarts = echarts
+
+Vue.use(ElementUI);
+Vue.config.productionTip = false
+
+new Vue({
+ render: h => h(App),
+}).$mount('#app')
diff --git a/benchmark/vue.config.js b/benchmark/vue.config.js
new file mode 100644
index 00000000000..54761742d76
--- /dev/null
+++ b/benchmark/vue.config.js
@@ -0,0 +1,5 @@
+const { defineConfig } = require('@vue/cli-service')
+module.exports = defineConfig({
+ publicPath: './',
+ transpileDependencies: true
+})
diff --git a/build_bh.sh b/build_bh.sh
new file mode 100644
index 00000000000..a04bf4ef68a
--- /dev/null
+++ b/build_bh.sh
@@ -0,0 +1,21 @@
+(cd ./benchmark && npm install && npm run build)
+
+for file in benchmark/dist/css/app.*.css; do
+ cp "$file" "static/css/app.css"
+ break
+done
+
+for file in benchmark/dist/css/chunk-vendors.*.css; do
+ cp "$file" "static/css/chunk-vendors.css"
+ break
+done
+
+for file in benchmark/dist/js/app.*.js; do
+ cp "$file" "static/js/app.js"
+ break
+done
+
+for file in benchmark/dist/js/chunk-vendors.*.js; do
+ cp "$file" "static/js/chunk-vendors.js"
+ break
+done
diff --git
a/content/zh-cn/overview/mannual/java-sdk/reference-manual/performance/page-benchmarking.md
b/content/zh-cn/overview/mannual/java-sdk/reference-manual/performance/page-benchmarking.md
new file mode 100644
index 00000000000..97d3c6594f9
--- /dev/null
+++
b/content/zh-cn/overview/mannual/java-sdk/reference-manual/performance/page-benchmarking.md
@@ -0,0 +1,26 @@
+---
+description: ""
+linkTitle: RPC 控制台
+title: RPC 基准测试 控制台
+type: html
+weight: 1
+---
+
+<html lang="">
+<head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width,initial-scale=1">
+ <title>dubbo-benchmark</title>
+ <script defer="defer" src="/js/chunk-vendors.js"></script>
+ <script defer="defer" src="/js/app.js"></script>
+ <link href="/css/chunk-vendors.css" rel="stylesheet">
+ <link href="/css/app.css" rel="stylesheet">
+</head>
+<body>
+<noscript><strong>We're sorry but dubbo-benchmark doesn't work properly
without JavaScript enabled. Please enable it to
+ continue.</strong></noscript>
+<div id="app"></div>
+</body>
+</html>
+
diff --git a/package.json b/package.json
index 59b56836322..289965c3f8b 100644
--- a/package.json
+++ b/package.json
@@ -13,8 +13,8 @@
},
"homepage": "https://dubbo.apache.org",
"devDependencies": {
- "autoprefixer": "^9.8.8",
- "postcss": "^8.4.21",
- "postcss-cli": "^7.1.2"
+ "autoprefixer": "^10.4.19",
+ "postcss": "^8.4.38",
+ "postcss-cli": "^11.0.0"
}
}
diff --git a/static/fonts/element-icons.f1a45d74.ttf
b/static/fonts/element-icons.f1a45d74.ttf
new file mode 100644
index 00000000000..91b74de3677
Binary files /dev/null and b/static/fonts/element-icons.f1a45d74.ttf differ
diff --git a/static/fonts/element-icons.ff18efd1.woff
b/static/fonts/element-icons.ff18efd1.woff
new file mode 100644
index 00000000000..02b9a2539e4
Binary files /dev/null and b/static/fonts/element-icons.ff18efd1.woff differ