将时间戳转为时间显示 date -d @978278400

percentile.h

https://github.com/chenshuo/muduo/blob/master/examples/sudoku/percentile.h


// this is not a standalone header fileclass Percentile
{public:Percentile(std::vector<int>& latencies, int infly){// latencies.size() 这1s的qps/rps,表示服务端处理多少个请求,infly表示有多少请求server没有处理完stat << "recv " << muduo::Fmt("%6zd", latencies.size()) << " in-fly " << infly;if (!latencies.empty()){// 将所有1s内server延迟时间排序std::sort(latencies.begin(), latencies.end());// 最小延迟时间int min = latencies.front();// 最大延迟时间int max = latencies.back();// 计算1s内延迟时间总和 int sum = std::accumulate(latencies.begin(), latencies.end(), 0);// 1s内响应延迟时间平均值int mean = sum / static_cast<int>(latencies.size());// 50%的请求延迟都小于medianint median = getPercentile(latencies, 50);// 90%的延迟都小于p90int p90 = getPercentile(latencies, 90);// 90%的延迟都小于p99int p99 = getPercentile(latencies, 99);stat << " min " << min<< " max " << max<< " avg " << mean<< " median " << median<< " p90 " << p90<< " p99 " << p99;}}const muduo::LogStream::Buffer& report() const{return stat.buffer();}void save(const std::vector<int>& latencies, muduo::StringArg name) const{if (latencies.empty())return;muduo::FileUtil::AppendFile f(name);f.append("# ", 2);f.append(stat.buffer().data(), stat.buffer().length());f.append("\n", 1);const int kInterval = 5; // 5 us per bucketint low = latencies.front() / kInterval * kInterval;int count = 0;int sum = 0;// 这1s的总共有多少个请求并且有响应const double total = static_cast<double>(latencies.size());char buf[64];
#ifndef NDEBUGfor (size_t i = 0; i < latencies.size(); ++i){int n = snprintf(buf, sizeof buf, "# %d\n", latencies[i]);f.append(buf, n);}
#endif// FIXME: improve this O(N) algorithm, maybe use lower_bound().// latencies此时已经排好序了for (size_t i = 0; i < latencies.size(); ++i){if (latencies[i] < low + kInterval)++count;else{sum += count;// count = [low, low+kInterval)这段时间有多少个请求,// 延迟时间小于low+kInterval的请求数量占总请求数量的百分比int n = snprintf(buf, sizeof buf, "%4d %5d %5.2f\n", low, count, 100 * sum / total);f.append(buf, n);low = latencies[i] / kInterval * kInterval;assert(latencies[i] < low + kInterval);count = 1;}}sum += count;assert(sum == total);int n = snprintf(buf, sizeof buf, "%4d %5d %5.1f\n", low, count, 100 * sum / total);f.append(buf, n);}private:static int getPercentile(const std::vector<int>& latencies, int percent){// The Nearest Rank methodassert(!latencies.empty());size_t idx = 0;if (percent > 0){idx = (latencies.size() * percent + 99) / 100 - 1;assert(idx < latencies.size());}return latencies[idx];}muduo::LogStream stat;
};

loadtest.cc

https://github.com/chenshuo/muduo/blob/master/examples/sudoku/loadtest.cc

#include "examples/sudoku/sudoku.h"#include "muduo/base/Logging.h"
#include "muduo/base/FileUtil.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpClient.h"#include <fstream>
#include <numeric>
#include <unordered_map>#include "examples/sudoku/percentile.h"#include <stdio.h>using namespace muduo;
using namespace muduo::net;typedef std::vector<string> Input;
typedef std::shared_ptr<const Input> InputPtr;InputPtr readInput(std::istream& in)
{std::shared_ptr<Input> input(new Input);std::string line;while (getline(in, line)){if (line.size() == implicit_cast<size_t>(kCells)){input->push_back(line.c_str());}}return input;
}class SudokuClient : noncopyable
{public:SudokuClient(EventLoop* loop,const InetAddress& serverAddr,const InputPtr& input,const string& name,bool nodelay): name_(name),tcpNoDelay_(nodelay),client_(loop, serverAddr, name_),input_(input),count_(0){client_.setConnectionCallback(std::bind(&SudokuClient::onConnection, this, _1));client_.setMessageCallback(std::bind(&SudokuClient::onMessage, this, _1, _2, _3));}void connect(){client_.connect();}void send(int n){assert(n > 0);if (!conn_)return;Timestamp now(Timestamp::now());for (int i = 0; i < n; ++i){char buf[256];// 计算需要文件的第几行为发送的请求参数const string& req = (*input_)[count_ % input_->size()];int len = snprintf(buf, sizeof buf, "%s-%08d:%s\r\n",name_.c_str(), count_, req.c_str());requests_.append(buf, len);// 保留已经发送的请求数量,key为第几个发送的请求,value为发送的请求时间sendTime_[count_] = now;// 请求数量增加1++count_;}conn_->send(&requests_);}void report(std::vector<int>* latency, int* infly){// 这1s内所有请求的延迟latency->insert(latency->end(), latencies_.begin(), latencies_.end());// 清空上1s的延迟latencies_.clear();// 当前有多少请求没有收到*infly += static_cast<int>(sendTime_.size());}private:void onConnection(const TcpConnectionPtr& conn){if (conn->connected()){LOG_INFO << name_ << " connected";if (tcpNoDelay_)conn->setTcpNoDelay(true);conn_ = conn;}else{LOG_INFO << name_ << " disconnected";conn_.reset();// FIXME: exit}}void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp recvTime){size_t len = buf->readableBytes();while (len >= kCells + 2){const char* crlf = buf->findCRLF();if (crlf){string response(buf->peek(), crlf);buf->retrieveUntil(crlf + 2);len = buf->readableBytes();if (!verify(response, recvTime)){LOG_ERROR << "Bad response:" << response;conn->shutdown();break;}}else if (len > 100) // id + ":" + kCells + "\r\n"{LOG_ERROR << "Line is too long!";conn->shutdown();break;}else{break;}}}bool verify(const string& response, Timestamp recvTime){size_t colon = response.find(':');if (colon != string::npos){size_t dash = response.find('-');if (dash != string::npos && dash < colon){int id = atoi(response.c_str()+dash+1);// id 为发送的第几个请求,value为发送的请求时间std::unordered_map<int, Timestamp>::iterator sendTime = sendTime_.find(id);if (sendTime != sendTime_.end()){// id的请求响应延迟为latency_usint64_t latency_us = recvTime.microSecondsSinceEpoch() - sendTime->second.microSecondsSinceEpoch();// 将相应延迟加入latencies_latencies_.push_back(static_cast<int>(latency_us));// id为下表的请求已经收到了,从发送的请求中删除sendTime_.erase(sendTime);}else{LOG_ERROR << "Unknown id " << id << " of " << name_;}}}// FIXMEreturn true;}const string name_;const bool tcpNoDelay_;TcpClient client_;TcpConnectionPtr conn_;Buffer requests_;const InputPtr input_;int count_;std::unordered_map<int, Timestamp> sendTime_;std::vector<int> latencies_;
};class SudokuLoadtest : noncopyable
{public:SudokuLoadtest(): count_(0),ticks_(0),sofar_(0){}void runClient(const InputPtr& input, const InetAddress& serverAddr, int rps, int conn, bool nodelay){EventLoop loop;// 创建多少的连接到client端for (int i = 0; i < conn; ++i){Fmt f("c%04d", i+1);string name(f.data(), f.length());clients_.emplace_back(new SudokuClient(&loop, serverAddr, input, name, nodelay));clients_.back()->connect();}// 0.01秒向server发送一次请求 loop.runEvery(1.0 / kHz, std::bind(&SudokuLoadtest::tick, this, rps));// client端看见每1s,server响应延迟latency,还有多少请求没有收到loop.runEvery(1.0, std::bind(&SudokuLoadtest::tock, this));loop.loop();}private:void tick(int rps){// 执行发送请求的次数++++ticks_;// 计算本次每个client应该发送的请求数量int64_t reqs = rps * ticks_ / kHz - sofar_;// 已经发送的总请求数量sofar_ += reqs;if (reqs > 0){for (const auto& client : clients_){client->send(static_cast<int>(reqs));}}}void tock(){std::vector<int> latencies;int infly = 0;for (const auto& client : clients_){client->report(&latencies, &infly);}Percentile p(latencies, infly);// 计算这1s响应延迟的平均时间,最大延迟,最小延迟,50%的请求都在多少延迟之内LOG_INFO << p.report();char buf[64];snprintf(buf, sizeof buf, "r%04d", count_);p.save(latencies, buf);++count_;}std::vector<std::unique_ptr<SudokuClient>> clients_;int count_;// 执行多少发送请求int64_t ticks_;// 已经发送的请求数量int64_t sofar_;static const int kHz = 100;
};int main(int argc, char* argv[])
{int conn = 1;int rps = 100;bool nodelay = false;InetAddress serverAddr("127.0.0.1", 9981);switch (argc){case 6:nodelay = string(argv[5]) == "-n";// FALL THROUGHcase 5:conn = atoi(argv[4]);// FALL THROUGHcase 4:rps = atoi(argv[3]);// FALL THROUGHcase 3:serverAddr = InetAddress(argv[2], 9981);// FALL THROUGHcase 2:break;default:printf("Usage: %s input server_ip [requests_per_second] [connections] [-n]\n", argv[0]);return 0;}std::ifstream in(argv[1]);if (in){// vector<string> input; 每个index为文件的一行InputPtr input(readInput(in));printf("%zd requests from %s\n", input->size(), argv[1]);SudokuLoadtest test;test.runClient(input, serverAddr, rps, conn, nodelay);}else{printf("Cannot open %s\n", argv[1]);}
}

客户端压测server端计算qps以及不同延迟时间下响应数量所占百分比相关推荐

  1. TCP第三次握手失败的处理(Server端超时重传机制、RST包响应、SYN攻击)

    面试题: 在 TCP 建立连接的三次握手连接阶段,如果客户端发送的第三个ACK包丢了,那么客户端和服务端分别进行什么处理呢? 相信了解 tcp 协议的人,三次握手的过程肯定很了解了.第三次的 ack ...

  2. socket 编程入门教程(一)TCP server 端:6、创建“通讯 ”嵌套字

    这里的"通讯"加上了引号,是因为实际上所有的socket都有通讯的功能,只是在我们的例子中,之前那个socket只负责listen,而这个socket负责接受信息并echo回去. ...

  3. Linux下Socket编程之TCP Server端

    一.建模 绝大部分关于socket编程的教程总是从socket的概念开始讲起的.要知道,socket的初衷是个庞大的体系,TCP/IP只是这个庞大体系下一个很小的子集,而我们真正能用上的更是这个子集中 ...

  4. 10分钟上线 - 利用函数计算构建微信小程序的Server端

    摘要: 阿里云函数计算是一个事件驱动的全托管计算服务.通过函数计算,您无需管理服务器等基础设施,只需编写代码并上传.微信小程序是一种不需要下载安装即可使用的应用,它可以在微信内被便捷地获取和传播. 当 ...

  5. 口令红包-利用函数计算构建微信小程序的server端

    摘要: 阿里云函数计算是一个事件驱动的全托管计算服务.通过函数计算,您无需管理服务器等基础设施,只需编写代码并上传.微信小程序是一种不需要下载安装即可使用的应用,它可以在微信内被便捷地获取和传播. 当 ...

  6. socket下server端支持多客户端并发访问简单实现

    /* *Author: wainiwann *Source: 博客园 http://www.cnblogs.com/wainiwann *Remarks:  转载请说明出处!!! */ server端 ...

  7. Zabbix监控学习系列(2):agent的安装与Server端添加客户端

    Zabbix监控学习系列(2) 简介描述 1. windows的客户端安装 1. 1手动安装包安装,安装过程中配置 1. 2免安装压缩包,解压后修改配置文件 2. Linux的客户端安装 3.在Zab ...

  8. brpc源码学习(六)- brpc server 端整体流程

    brpc的使用比较容易上手,以官方demo为例,因为brpc的数据序列化依赖protobuf,所以首先需要定义个proto 然后继承EchoService并实现Echo方法 然后是整体流程 启动还是比 ...

  9. 利用Serverless构建微信小程序的Server端

    前言 这篇文章适合所有的想微信小程序开发新手.老鸟以及想准备学习开发微信小程序的程序猿.本文以开发一个类似"语音口令红包"小程序为例,向您讲解如何使用阿里云函数计算快速构建微信小程 ...

最新文章

  1. [webapi] 如何在查看api时 显示api的说明
  2. windows server 2008的安装以及主机IP配置实验
  3. 企业网络推广方案分享如何针对大量的长尾词进行更好地优化方法!
  4. OpenGL 加载模型Model
  5. Linux命令【二】终端+Vim
  6. ML Backpropagation算法实现的过程举例
  7. Maven打包自动发布到nexus私服
  8. html语言标示,HTML语言剖析(二) HTML标记一览
  9. BJOI2018 简要题解
  10. 夺命雷公狗---linux NO:26 linux下的用户和用户组的管理
  11. Gatekeeper:首个开源的DDoS防护系统
  12. linux下ftp客户端主动模式设置
  13. 苏州银行对公存款业务模块维护
  14. 移动硬盘linux双系统,安装ubuntu到移动硬盘(UEFI+GPT),实现在别的电脑也可以使用(详细教程),...
  15. python 经典图书排行榜_知乎必读书单排行榜
  16. 009 极限的四则运算定理(加、减、乘、除)
  17. UDP 实现多收多发,广播发送,组播发送 TCP 实现多收多发
  18. springbootadmin 客户端监控配置
  19. 如何用ps扣字体_如何用PS的字体扣出来,改变颜色.PS如何抠图?
  20. 三剑客之Docker Swarm

热门文章

  1. 利用DllPlugin分割你的第三方库
  2. Ajax (部分二:prototype.js代码后半部分)自己做的,总结页面向后台传Form值、单个值和后台向前台传一个或是一组值...
  3. C++Primer第5版学习笔记(一)
  4. 一起谈.NET技术,ASP.NET MVC 通过 FileResult 向浏览器发送文件
  5. 11种刷新按钮的方法
  6. C++ 解引用操作符重载
  7. python程序打包exe
  8. linux命令快速手记 — 让手指跟上思考的速度(四)
  9. Webpack + vue + es6 安装
  10. Newtonsoft.Json 方法使用()