Skip to content

Commit

Permalink
Merge pull request #31 from cha87de/profiler
Browse files Browse the repository at this point in the history
Integrate Profiler into Master
  • Loading branch information
cha87de committed May 29, 2019
2 parents 42e70c8 + 1f78bfa commit a042a7b
Show file tree
Hide file tree
Showing 24 changed files with 526 additions and 77 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
_builder/do
12 changes: 10 additions & 2 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ builds:
- linux
goarch:
- amd64
- main: ./cmd/kvmprofiler
binary: kvmprofiler
goos:
- linux
goarch:
- amd64

nfpm:
name_template: "{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
Expand All @@ -27,6 +33,7 @@ nfpm:
# additional files, e.g. systemd service
files:
"pkgbuild/kvmtop.service": "/etc/systemd/system/kvmtop.service"
"pkgbuild/kvmprofiler.service": "/etc/systemd/system/kvmprofiler.service"
config_files:
"pkgbuild/kvmtop.conf": "/etc/kvmtop.conf"

Expand All @@ -35,7 +42,8 @@ dockers:
goos: linux
goarch: amd64
goarm: ''
binary: kvmtop
image_templates:
- 'cha87de/kvmtop:{{ .Tag }}'
- 'cha87de/kvmtop:latest'
extra_files:
- init
- dist/linux_amd64
11 changes: 7 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
language: go
go:
- '1.9'
- '1.11.5'

services:
- docker
Expand All @@ -11,20 +11,23 @@ before_install:

install:
- "go get -d -v ./..."
#- "go get github.com/tools/godep"
#- "(cd cmd/kvmprofiler/ ; godep restore)"
# - "(cd cmd/kvmtop/ ; godep restore)"
- "go install ./..."
- "cp $GOPATH/bin/kvmtop ."
- "mkdir -p dist/linux_amd64 ; cp $GOPATH/bin/kvm* ./dist/linux_amd64/"

before_deploy:
- echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin

deploy:
- provider: script
skip_cleanup: true
script: docker build -t cha87de/kvmtop:master . ; docker push cha87de/kvmtop:master
script: docker build --no-cache -t cha87de/kvmtop:master . ; docker push cha87de/kvmtop:master
on:
branch: master
- provider: script
script: curl -sL https://git.io/goreleaser | bash
script: rm -rf dist/linux_amd64; curl -sL https://git.io/goreleaser | bash
on:
tags: true
condition: $TRAVIS_OS_NAME = linux
24 changes: 21 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
FROM alpine:latest
RUN apk update
RUN apk add libvirt-client ncurses5-libs
RUN apk add libvirt-client ncurses5-libs git gettext curl bash make
RUN mkdir /lib64 && ln -s /lib/libc.musl-x86_64.so.1 /lib64/ld-linux-x86-64.so.2
RUN ln -s /usr/lib/libncurses.so.5 /usr/lib/libtinfo.so.5
ADD kvmtop /bin/kvmtop
CMD [ "/bin/kvmtop" ]

# use bpkg to handle complex bash entrypoints
RUN curl -Lo- "https://raw.githubusercontent.com/bpkg/bpkg/master/setup.sh" | bash
RUN bpkg install cha87de/bashutil -g

# copy entrypoint
RUN mkdir -p /opt/docker-init
ADD init /opt/docker-init

# add kvmtop binaries
ADD dist/linux_amd64/kvmtop /bin/kvmtop
ADD dist/linux_amd64/kvmprofiler /bin/kvmprofiler

# set parameters
ENV PARAMS "-c qemu:///system --printer=text --cpu --mem --net --disk"
ENV PROFILER_PARAMS "--states 4 --history 1 --filterstddevs 12 --outputFreq 20"

# start from init folder
WORKDIR /opt/docker-init
ENTRYPOINT ["./entrypoint"]
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/cha87de/kvmtop.svg)](https://travis-ci.org/cha87de/kvmtop)
[![Build Status](https://travis-ci.org/cha87de/kvmtop.svg?branch=master)](https://travis-ci.org/cha87de/kvmtop)
[![GitHub release](https://img.shields.io/github/release/cha87de/kvmtop.svg)](https://github.com/cha87de/kvmtop/releases)
[![GitHub stars](https://img.shields.io/github/stars/cha87de/kvmtop.svg?style=social&label=Stars)](https://github.com/cha87de/kvmtop)
[![Go Report Card](https://goreportcard.com/badge/github.com/cha87de/kvmtop)](https://goreportcard.com/report/github.com/cha87de/kvmtop)
Expand Down
72 changes: 72 additions & 0 deletions cmd/kvmprofiler/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package main

import (
"fmt"
"os"
"strconv"
"strings"

"github.com/cha87de/kvmtop/collectors/cpucollector"
"github.com/cha87de/kvmtop/collectors/iocollector"
"github.com/cha87de/kvmtop/collectors/netcollector"
"github.com/cha87de/kvmtop/config"
"github.com/cha87de/kvmtop/models"
flags "github.com/jessevdk/go-flags"
)

func initializeFlags() {
// initialize parser for flags
parser := flags.NewParser(&config.Options, flags.Default)
parser.ShortDescription = "kvmprofiler"
parser.LongDescription = "Compute statistical profiles from monitoring data of virtual machines via kvmtop"

// Parse parameters
if _, err := parser.Parse(); err != nil {
code := 1
if fe, ok := err.(*flags.Error); ok {
if fe.Type == flags.ErrHelp {
code = 0
}
}
if code != 0 {
fmt.Printf("Error parsing flags: %s\n", err)
}
os.Exit(code)
}

// Set collectors from flags
if config.Options.EnableCPU {
collector := cpucollector.CreateCollector()
models.Collection.Collectors.Store("cpu", &collector)
}
if config.Options.EnableMEM {
fmt.Println("memory profiling not supported.")
}
if config.Options.EnableDISK {
fmt.Println("disk profiling not supported.")
}
if config.Options.EnableNET {
collector := netcollector.CreateCollector()
models.Collection.Collectors.Store("net", &collector)
}
if config.Options.EnableIO {
collector := iocollector.CreateCollector()
models.Collection.Collectors.Store("io", &collector)
}
if config.Options.EnableHost {
fmt.Println("host profiling not supported.")
}

// Parse periodsize csv string
periodSizeStr := strings.Split(config.Options.Profiler.PeriodSize, ",")
periodSize := make([]int, 0)
for _, s := range periodSizeStr {
if s == "" {
continue
}
si, _ := strconv.Atoi(s)
periodSize = append(periodSize, si)
}
config.Options.Profiler.PeriodSizeParsed = periodSize

}
41 changes: 41 additions & 0 deletions cmd/kvmprofiler/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import (
"fmt"
"os"
"sync"

"github.com/cha87de/kvmtop/config"
"github.com/cha87de/kvmtop/connector"
"github.com/cha87de/kvmtop/models"
"github.com/cha87de/kvmtop/profiler"
"github.com/cha87de/kvmtop/runners"
)

func main() {

// handle flags
initializeFlags()

// connect to libvirt
connector.Libvirt.ConnectionURI = config.Options.LibvirtURI
err := connector.InitializeConnection()
if err != nil {
fmt.Println("failed to initialize connection to libvirt. kvmprofile will terminate.")
os.Exit(1)
}

// initialize host measureable
models.Collection.Host = &models.Host{
Measurable: &models.Measurable{},
}

// start lookup and collect runners
var wg sync.WaitGroup
wg.Add(1) // terminate when first thread terminates
go runners.InitializeLookup(&wg)
go runners.InitializeCollect(&wg)
go profiler.InitializeProfiler(&wg)
wg.Wait()

}
10 changes: 5 additions & 5 deletions collectors/cpucollector/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ func cpuPrint(domain *models.Domain) []string {
cores := collectors.GetMetricUint64(domain.Measurable, "cpu_cores", 0)

// cpu util for vcores
cputimeAllCores := cpuPrintThreadMetric(domain, "cpu_threadIDs", "cpu_times")
queuetimeAllCores := cpuPrintThreadMetric(domain, "cpu_threadIDs", "cpu_runqueues")
cputimeAllCores := CpuPrintThreadMetric(domain, "cpu_threadIDs", "cpu_times")
queuetimeAllCores := CpuPrintThreadMetric(domain, "cpu_threadIDs", "cpu_runqueues")

// cpu util for for other threads (i/o or emulation)
otherCputimeAllCores := cpuPrintThreadMetric(domain, "cpu_otherThreadIDs", "cpu_other_times")
otherQueuetimeAllCores := cpuPrintThreadMetric(domain, "cpu_otherThreadIDs", "cpu_other_runqueues")
otherCputimeAllCores := CpuPrintThreadMetric(domain, "cpu_otherThreadIDs", "cpu_other_times")
otherQueuetimeAllCores := CpuPrintThreadMetric(domain, "cpu_otherThreadIDs", "cpu_other_runqueues")

// put results together
result := append([]string{cores}, cputimeAllCores, queuetimeAllCores)
Expand All @@ -122,7 +122,7 @@ func cpuPrint(domain *models.Domain) []string {
return result
}

func cpuPrintThreadMetric(domain *models.Domain, lookupMetric string, metric string) string {
func CpuPrintThreadMetric(domain *models.Domain, lookupMetric string, metric string) string {
threadIDs := domain.GetMetricIntArray(lookupMetric)
var measurementSum float64
var measurementCount int
Expand Down
13 changes: 9 additions & 4 deletions config/options.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package config

// Options holds set of runtime configuration parameters
var Options struct {
// OptionsType defines the runtime configuration parameters
type OptionsType struct {
Version bool `short:"v" long:"version" description:"Show version"`
Frequency int `short:"f" long:"frequency" description:"Frequency (in seconds) for collecting metrics" default:"1"`
Runs int `short:"r" long:"runs" description:"Amount of collection runs" default:"-1"`
Expand All @@ -18,8 +18,13 @@ var Options struct {

Printer string `short:"p" long:"printer" description:"the output printer to use (valid printers: ncurses, text, json)" default:"ncurses"`

Output string `short:"o" long:"output" description:"the output channel to send printer output (valid output: stdout, file, tcp)" default:"stdout"`
OutputTarget string `long:"target" description:"for output 'file' the location, for 'tcp' the url to the tcp server"`
Output string `short:"o" long:"output" description:"the output channel to send printer output (valid output: stdout, file, tcp, udp)" default:"stdout"`
OutputTarget string `long:"target" description:"for output 'file' the location, for 'tcp' or 'udp' the url (host:port) to the server"`

NetworkDevice string `long:"netdev" description:"The network device used for the virtual traffic"`

Profiler ProfilerOptionsType `group:"Profiler Options"`
}

// Options holds the OptionsType configuration parameters
var Options OptionsType
16 changes: 16 additions & 0 deletions config/profiler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package config

import "time"

// ProfilerOptionsType describes profiler options
type ProfilerOptionsType struct {
States int `long:"states" default:"4"`
BufferSize int `long:"buffersize" default:"10"`
History int `long:"history" default:"1"`
FilterStdDevs int `long:"filterstddevs" default:"-1"`
FixedBound bool `long:"fixedbound"`
PeriodSize string `long:"periodsize" default:"" description:"comma separated list of ints, specifies descrete states per period"`
OutputFreq time.Duration `long:"outputFreq" default:"60"`

PeriodSizeParsed []int
}
44 changes: 44 additions & 0 deletions init/entrypoint
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/bash

# include bpkg dependencies
source /usr/local/bin/retry
source /usr/local/bin/bgo
source /usr/local/bin/bgowait

##############################################################################
function start_metrics(){
kvmtop $PARAMS
}
function start_profiler(){
kvmprofiler $PARAMS $PROFILER_PARAMS
}
function start(){
echo "starting applications..."
bgo start_metrics start_profiler
if [[ $? != 0 ]]; then
echo "start failed. exiting now." >&2
exit 1
fi
}

##############################################################################
function main(){
# start
start
if [[ $? != 0 ]]; then
echo "start failed. exiting now." >&2
exit 1
fi

# wait
echo "done. now waiting for services."
#freq=5; waitForN=-1; killTasks=0 # fail one, ignore (development mode)
freq=5; waitForN=1; killTasks=1 #fail one, fail all (production mode)
bgowait $freq $waitForN $killTasks
}

if [[ "$1" == "" ]]; then
main
else
exec "$@"
fi
13 changes: 13 additions & 0 deletions pkgbuild/kvmprofiler.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[Unit]
Description=Profiler for virtual machine monitoring kvmtop
After=libvirtd.service

[Service]
Type=simple
Restart=always
RestartSec=3
EnvironmentFile=/etc/kvmtop.conf
ExecStart=/usr/bin/kvmprofiler --printer=json --output=tcp --target=${KVMTOP_TARGET} --cpu --net --mem --io --disk --host --verbose ${KVMPROFILER_PARAMS}

[Install]
WantedBy=multi-user.target
3 changes: 2 additions & 1 deletion pkgbuild/kvmtop.conf
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
KVMTOP_TARGET=192.168.50.230:12345
KVMTOP_TARGET=192.168.50.230:12345
KVMPROFILER_PARAMS="--states 4 --history 1 --filterstddevs 256 --outputFreq 60s --buffersize 10"
Loading

0 comments on commit a042a7b

Please sign in to comment.