Skip to content

Commit

Permalink
fix distribution metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
lv 周 authored and lv 周 committed May 9, 2022
1 parent 0af11f1 commit f5d08f4
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 25 deletions.
42 changes: 39 additions & 3 deletions http_bench.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,13 @@ type StressResult struct {
SizeTotal int64 `json:"size_total"`
Duration int64 `json:"duration"`
Output string `json:"output"`
rdLock sync.RWMutex `json:"-"`
}

func (result *StressResult) print() {
result.rdLock.Lock()
defer result.rdLock.Unlock()

switch result.Output {
case "csv":
fmt.Printf("Duration,Count\n")
Expand Down Expand Up @@ -233,6 +237,9 @@ func (result *StressResult) print() {

// Print latency distribution.
func (result *StressResult) printLatencies() {
result.rdLock.Lock()
defer result.rdLock.Unlock()

pctls := []int{10, 25, 50, 75, 90, 95, 99}
data := make([]string, len(pctls))
durationLats := make([]string, 0)
Expand All @@ -257,19 +264,32 @@ func (result *StressResult) printLatencies() {

// Print status code distribution.
func (result *StressResult) printStatusCodes() {
result.rdLock.Lock()
defer result.rdLock.Unlock()

fmt.Printf("\nStatus code distribution:\n")
for code, num := range result.StatusCodeDist {
fmt.Printf(" [%d]\t%d responses\n", code, num)
}
}

func (result *StressResult) printErrors() {
result.rdLock.Lock()
defer result.rdLock.Unlock()

fmt.Printf("\nError distribution:\n")
for err, num := range result.ErrorDist {
fmt.Printf(" [%d]\t%s\n", num, err)
}
}

func (result *StressResult) marshal() ([]byte, error) {
result.rdLock.Lock()
defer result.rdLock.Unlock()

return json.Marshal(result)
}

type StressParameters struct {
// Sequence
SequenceId int64 `json:"sequence_id"`
Expand Down Expand Up @@ -367,6 +387,11 @@ func (b *StressWorker) Wait() *StressResult {
return nil
}

verbosePrint(VERBOSE_DEBUG, "resultList len: %d\n", len(b.resultList))

b.resultList[0].rdLock.Lock()
defer b.resultList[0].rdLock.Unlock()

if len(b.resultList) > 1 {
for _, v := range b.resultList[1:] {
if b.resultList[0].Slowest < v.Slowest {
Expand Down Expand Up @@ -578,9 +603,11 @@ func (b *StressWorker) collectReport() {
for {
select {
case res, ok := <-b.results:
b.currentResult.rdLock.Lock()
if !ok {
b.currentResult.Duration = int64(b.totalTime.Seconds() * SCALE_NUM)
b.resultList = append(b.resultList, b.currentResult)
b.currentResult.rdLock.Unlock()
return
}
if res.err != nil {
Expand All @@ -601,6 +628,7 @@ func (b *StressWorker) collectReport() {
b.currentResult.SizeTotal += res.contentLength
}
}
b.currentResult.rdLock.Unlock()
case <-timeTicker.C:
verbosePrint(VERBOSE_INFO, "Time ticker upcoming, duration: %ds\n", b.RequestParams.Duration)
b.Stop(false) // Time ticker exec Stop commands
Expand Down Expand Up @@ -736,13 +764,21 @@ func execStress(params StressParameters, stressTestPtr **StressWorker) *StressRe
}
stressList.Delete(params.SequenceId)
case CMD_STOP:
if len(workerList) > 0 {
jsonBody, _ := json.Marshal(params)
requestWorkerList(jsonBody, stressTest)
}
stressTest.Stop(true)
stressList.Delete(params.SequenceId)
case CMD_METRICS:
if len(workerList) > 0 {
jsonBody, _ := json.Marshal(params)
resultList := requestWorkerList(jsonBody, stressTest)
stressTest.Append(resultList...)
if resultList := requestWorkerList(jsonBody, stressTest); len(resultList) > 0 {
stressResult = &StressResult{}
for i := 0; i < len(resultList); i++ {
stressResult.LatsTotal += resultList[i].LatsTotal
} // TODO: dispose other variable
}
} else {
stressResult = &stressTest.currentResult
}
Expand All @@ -759,7 +795,7 @@ func handleWorker(w http.ResponseWriter, r *http.Request) {
verbosePrint(VERBOSE_DEBUG, "Request params: %s\n", params.String())
var stressWorker *StressWorker
if result := execStress(params, &stressWorker); result != nil {
if wbody, err := json.Marshal(result); err != nil {
if wbody, err := result.marshal(); err != nil {
verbosePrint(VERBOSE_ERROR, "Marshal result: %v\n", err)
} else {
w.Write(wbody)
Expand Down
123 changes: 101 additions & 22 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,118 @@
<div style="margin: 5px;">
<div class="form-group">
<label for="requestForm">Input Request:</label>
<button type="button" class="btn btn-outline-success" click="start">Start</button>
<button type="button" class="btn btn-outline-danger" click="stop">Stop</button>
<button type="button" class="btn btn-outline-success" onclick="submitStart()">Start</button>
<button type="button" class="btn btn-outline-danger" onclick="submitStop()">Stop</button>
</div>
<div class="form-group">
<textarea class="form-control" id="requestForm" rows="10"></textarea>
<textarea class="form-control" id="requestForm" rows="10">
{
"request_method": "GET",
"request_body": "",
"request_httptype": "http1",
"n": 0,
"c": 1,
"duration": 1000,
"timeout": 3000,
"qps": 0,
"disable_compression": false,
"disable_keepalives": false,
"auth_username": "",
"auth_password": "",
"headers": null,
"urls": ["http://9.134.13.199:8000?data=1"],
"output": ""
}</textarea>
</div>
</div>
<script type="text/javascript">
Date.prototype.format = function(fmt) {
var o = {
"M+" : this.getMonth()+1,
"d+" : this.getDate(),
"h+" : this.getHours(),
"m+" : this.getMinutes(),
"s+" : this.getSeconds(),
"q+" : Math.floor((this.getMonth()+3)/3),
"S" : this.getMilliseconds()
};
if(/(y+)/.test(fmt)) {
fmt=fmt.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
}
for(var k in o) {
if(new RegExp("("+ k +")").test(fmt)){
fmt = fmt.replace(RegExp.$1, (RegExp.$1.length==1) ? (o[k]) : (("00"+ o[k]).substr((""+ o[k]).length)));
}
}
return fmt;
}
var seqid = Math.floor(Math.random() * 1000000) + 1;
var interval;
function submitStart(e) {
seqid = seqid + 1;
var requestData = JSON.parse(document.getElementById("requestForm").innerHTML);
requestData.cmd = 0;
requestData.sequence_id = seqid;
fetch('/api', {
method: 'POST',
headers: {'Content-Type': 'application/json;charset=utf-8'},
body: JSON.stringify(requestData)
}).then(response => response.json());
var timeList = [], dataList = [], latsTotal = 0;
interval = setInterval(function() {
requestData.cmd = 2;
fetch('/api', {
method: 'POST',
headers: {'Content-Type': 'application/json;charset=utf-8'},
body: JSON.stringify(requestData)
}).then(response => response.json()).then(data => {
if (data && data.lats_total) {
timeList.push(new Date().format("hh:mm:ss"));
dataList.push(data.lats_total - latsTotal);
metricsLoad(timeList, dataList);
latsTotal = data.lats_total;
}
})
}, 1000)
}
function submitStop(e) {
clearInterval(interval);
var requestData = JSON.parse(document.getElementById("requestForm").innerHTML);
requestData.cmd = 1;
requestData.sequence_id = seqid;
fetch('/api', {
method: 'POST',
headers: {'Content-Type': 'application/json;charset=utf-8'},
body: JSON.stringify(requestData)
});
}
var dom = document.getElementById('container');
var stressChart = echarts.init(dom, 'dark', {
renderer: 'canvas',
useDirtyRect: false
});
var app = {};
var option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [
{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line',
smooth: true
}
]
};
if (option && typeof option === 'object') {
stressChart.setOption(option);
function metricsLoad(timeList, dataList) {
var option = {
xAxis: {
type: 'category',
data: timeList
},
yAxis: {
type: 'value'
},
series: [
{
data: dataList,
type: 'line',
smooth: true
}
]
};
if (option && typeof option === 'object') {
stressChart.setOption(option);
}
}
metricsLoad([new Date().format("hh:mm:ss")], [0])
window.addEventListener('resize', stressChart.resize);
</script>
</body>
Expand Down

0 comments on commit f5d08f4

Please sign in to comment.