Skip to content

Commit

Permalink
show CPU usage chart in procmon.
Browse files Browse the repository at this point in the history
  • Loading branch information
chenshuo committed Nov 18, 2014
1 parent e43a7a2 commit 86cfbc0
Show file tree
Hide file tree
Showing 7 changed files with 329 additions and 58 deletions.
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ find_path(TCMALLOC_INCLUDE_DIR google/heap-profiler.h)
find_library(TCMALLOC_LIBRARY NAMES tcmalloc_and_profiler)
find_path(HIREDIS_INCLUDE_DIR hiredis/hiredis.h)
find_library(HIREDIS_LIBRARY NAMES hiredis)
find_path(GD_INCLUDE_DIR gd.h)
find_library(GD_LIBRARY NAMES gd)

if(CARES_INCLUDE_DIR AND CARES_LIBRARY)
message(STATUS "found cares")
Expand All @@ -73,6 +75,9 @@ endif()
if(HIREDIS_INCLUDE_DIR AND HIREDIS_LIBRARY)
message(STATUS "found hiredis")
endif()
if(GD_INCLUDE_DIR AND GD_LIBRARY)
message(STATUS "found gd")
endif()

include_directories(${Boost_INCLUDE_DIRS})

Expand Down
7 changes: 6 additions & 1 deletion examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ add_subdirectory(netty/discard)
add_subdirectory(netty/echo)
add_subdirectory(netty/uptime)
add_subdirectory(pingpong)
add_subdirectory(procmon)
add_subdirectory(roundtrip)
add_subdirectory(shorturl)
add_subdirectory(simple)
Expand Down Expand Up @@ -48,3 +47,9 @@ if(HIREDIS_INCLUDE_DIR AND HIREDIS_LIBRARY)
else()
add_subdirectory(hiredis EXCLUDE_FROM_ALL)
endif()

if(GD_INCLUDE_DIR AND GD_LIBRARY)
add_subdirectory(procmon)
else()
add_subdirectory(procmon EXCLUDE_FROM_ALL)
endif()
7 changes: 5 additions & 2 deletions examples/procmon/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
add_executable(procmon procmon.cc)
target_link_libraries(procmon muduo_http)
add_executable(procmon procmon.cc plot.cc)
target_link_libraries(procmon muduo_http gd)

add_executable(plot_test plot_test.cc plot.cc)
target_link_libraries(plot_test muduo_base gd)
112 changes: 112 additions & 0 deletions examples/procmon/plot.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#include "plot.h"
#include <algorithm>

#include <math.h>

#include <gd.h>
#include <gdfonts.h>

struct Plot::MyGdFont : public gdFont {};

Plot::Plot(int width, int height, int totalSeconds, int samplingPeriod)
: width_(width),
height_(height),
totalSeconds_(totalSeconds),
samplingPeriod_(samplingPeriod),
image_(gdImageCreate(width_, height_)),
font_(static_cast<MyGdFont*>(gdFontGetSmall())),
fontWidth_(font_->w),
fontHeight_(font_->h),
white_(gdImageColorAllocate(image_, 255, 255, 240)),
black_(gdImageColorAllocate(image_, 0, 0, 0)),
gray_(gdImageColorAllocate(image_, 200, 200, 200)),
kRightMargin_(3 * fontWidth_ + 5),
ratioX_(static_cast<double>(samplingPeriod_ * (width_ - kLeftMargin_ - kRightMargin_)) / totalSeconds_)
{
// gdImageSetAntiAliased(image_, black_);
}

Plot::~Plot()
{
gdImageDestroy(image_);
}

muduo::string Plot::plotCpu(const std::vector<double> data)
{
gdImageFilledRectangle(image_, 0, 0, width_, height_, white_);
if (data.size() > 1)
{
gdImageSetThickness(image_, 2);
double max = *std::max_element(data.begin(), data.end());
max = std::max(0.1, ceil(max*10.0) / 10.0);
label(max);

for (size_t i = 0; i < data.size()-1; ++i)
{
gdImageLine(image_,
getX(i, data.size()),
getY(data[i] / max),
getX(i+1, data.size()),
getY(data[i+1]/max),
black_);
}
}

int total = totalSeconds_/samplingPeriod_;
gdImageSetThickness(image_, 1);
gdImageLine(image_, getX(0, total), getY(0)+2, getX(total, total), getY(0)+2, gray_);
gdImageLine(image_, getX(total, total), getY(0)+2, getX(total, total), getY(1)+2, gray_);
return toPng();
}

void Plot::label(double maxValue)
{
char buf[64];
if (maxValue >= 10.0)
snprintf(buf, sizeof buf, "%.0f", maxValue);
else
snprintf(buf, sizeof buf, "%.1f", maxValue);

gdImageString(image_,
font_,
width_ - kRightMargin_ + 3,
kMarginY_ - 3,
reinterpret_cast<unsigned char*>(buf),
black_);

snprintf(buf, sizeof buf, "0");
gdImageString(image_,
font_,
width_ - kRightMargin_ + 3,
height_ - kMarginY_ - 3 - fontHeight_ / 2,
reinterpret_cast<unsigned char*>(buf),
black_);

snprintf(buf, sizeof buf, "-%ds", totalSeconds_);
gdImageString(image_,
font_,
kLeftMargin_,
height_ - kMarginY_ - fontHeight_,
reinterpret_cast<unsigned char*>(buf),
black_);
}

int Plot::getX(ssize_t i, ssize_t total) const
{
double x = (width_ - kLeftMargin_ - kRightMargin_) + static_cast<double>(i - total) * ratioX_;
return static_cast<int>(x + 0.5) + kLeftMargin_;
}

int Plot::getY(double value) const
{
return static_cast<int>((1.0 - value) * (height_-2*kMarginY_) + 0.5) + kMarginY_;
}

muduo::string Plot::toPng()
{
int size = 0;
void* png = gdImagePngPtr(image_, &size);
muduo::string result(static_cast<char*>(png), size);
gdFree(png);
return result;
}
41 changes: 41 additions & 0 deletions examples/procmon/plot.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <muduo/base/Types.h>
#include <vector>
#include <boost/noncopyable.hpp>

typedef struct gdImageStruct* gdImagePtr;

class Plot : boost::noncopyable
{
public:
Plot(int width, int height, int totalSeconds, int samplingPeriod);
~Plot();
muduo::string plotCpu(const std::vector<double> data);

private:
muduo::string toPng();
int getX(long x, long total) const;
int getY(double value) const;
void label(double maxValue);

struct MyGdFont;
typedef struct MyGdFont* MyGdFontPtr;

const int width_;
const int height_;
const int totalSeconds_;
const int samplingPeriod_;
const gdImagePtr image_;
const MyGdFontPtr font_; // no way to forward declaration gdFontPtr
const int fontWidth_;
const int fontHeight_;
const int white_;
const int black_;
const int gray_;

const int kRightMargin_;
static const int kLeftMargin_ = 5;
static const int kMarginY_ = 5;

const double ratioX_;
};

17 changes: 17 additions & 0 deletions examples/procmon/plot_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "plot.h"
#include <vector>
#include <math.h>
#include <stdio.h>

int main()
{
std::vector<double> cpu_usage;
for (int i = 0; i < 300; ++i)
cpu_usage.push_back(1.0 + sin(pow(i / 30.0, 2)));
Plot plot(600, 100, 600, 2);
muduo::string png = plot.plotCpu(cpu_usage);

FILE* fp = fopen("test.png", "wb");
fwrite(png.data(), 1, png.size(), fp);
fclose(fp);
}
Loading

0 comments on commit 86cfbc0

Please sign in to comment.