Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
457548ef
Commit
457548ef
authored
Jun 21, 2018
by
Shyam Jeedigunta
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor profile-gatherer to work across all master components
parent
83ad4d9e
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
64 additions
and
49 deletions
+64
-49
profile_gatherer.go
test/e2e/framework/profile_gatherer.go
+60
-45
density.go
test/e2e/scalability/density.go
+2
-2
load.go
test/e2e/scalability/load.go
+2
-2
No files found.
test/e2e/framework/profile_gatherer.go
View file @
457548ef
...
...
@@ -61,25 +61,54 @@ func checkProfileGatheringPrerequisites() error {
return
nil
}
func
gatherProfileOfKind
(
profileBaseName
,
kind
string
)
error
{
func
getPortForComponent
(
componentName
string
)
(
int
,
error
)
{
switch
componentName
{
case
"kube-apiserver"
:
return
8080
,
nil
case
"kube-scheduler"
:
return
10251
,
nil
case
"kube-controller-manager"
:
return
10252
,
nil
}
return
-
1
,
fmt
.
Errorf
(
"Port for component %v unknown"
,
componentName
)
}
// Gathers profiles from a master component through SSH. E.g usages:
// - gatherProfile("kube-apiserver", "someTest", "heap")
// - gatherProfile("kube-scheduler", "someTest", "profile")
// - gatherProfile("kube-controller-manager", "someTest", "profile?seconds=20")
//
// We don't export this method but wrappers around it (see below).
func
gatherProfile
(
componentName
,
profileBaseName
,
profileKind
string
)
error
{
if
err
:=
checkProfileGatheringPrerequisites
();
err
!=
nil
{
return
fmt
.
Errorf
(
"Profile gathering pre-requisite failed: %v"
,
err
)
}
profilePort
,
err
:=
getPortForComponent
(
componentName
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Profile gathering failed finding component port: %v"
,
err
)
}
if
profileBaseName
==
""
{
profileBaseName
=
time
.
Now
()
.
Format
(
time
.
RFC3339
)
}
// Get the profile data over SSH.
getCommand
:=
fmt
.
Sprintf
(
"curl -s localhost:
8080/debug/pprof/%s"
,
k
ind
)
getCommand
:=
fmt
.
Sprintf
(
"curl -s localhost:
%v/debug/pprof/%s"
,
profilePort
,
profileK
ind
)
sshResult
,
err
:=
SSH
(
getCommand
,
GetMasterHost
()
+
":22"
,
TestContext
.
Provider
)
if
err
!=
nil
{
return
fmt
.
Errorf
(
"Failed to execute curl command on master through SSH: %v"
,
err
)
}
var
profilePrefix
string
profilePrefix
:=
componentName
switch
{
case
k
ind
==
"heap"
:
profilePrefix
=
"Apiserver
MemoryProfile_"
case
strings
.
HasPrefix
(
k
ind
,
"profile"
)
:
profilePrefix
=
"Apiserver
CPUProfile_"
case
profileK
ind
==
"heap"
:
profilePrefix
+=
"_
MemoryProfile_"
case
strings
.
HasPrefix
(
profileK
ind
,
"profile"
)
:
profilePrefix
+=
"_
CPUProfile_"
default
:
return
fmt
.
Errorf
(
"Unknown profile kind provided: %s"
,
k
ind
)
return
fmt
.
Errorf
(
"Unknown profile kind provided: %s"
,
profileK
ind
)
}
// Write the data to a file.
// Write the
profile
data to a file.
rawprofilePath
:=
path
.
Join
(
getProfilesDirectoryPath
(),
profilePrefix
+
profileBaseName
+
".pprof"
)
rawprofile
,
err
:=
os
.
Create
(
rawprofilePath
)
if
err
!=
nil
{
...
...
@@ -97,12 +126,12 @@ func gatherProfileOfKind(profileBaseName, kind string) error {
var
cmd
*
exec
.
Cmd
switch
{
// TODO: Support other profile kinds if needed (e.g inuse_space, alloc_objects, mutex, etc)
case
k
ind
==
"heap"
:
case
profileK
ind
==
"heap"
:
cmd
=
exec
.
Command
(
"go"
,
"tool"
,
"pprof"
,
"-pdf"
,
"-symbolize=none"
,
"--alloc_space"
,
rawprofile
.
Name
())
case
strings
.
HasPrefix
(
k
ind
,
"profile"
)
:
case
strings
.
HasPrefix
(
profileK
ind
,
"profile"
)
:
cmd
=
exec
.
Command
(
"go"
,
"tool"
,
"pprof"
,
"-pdf"
,
"-symbolize=none"
,
rawprofile
.
Name
())
default
:
return
fmt
.
Errorf
(
"Unknown profile kind provided: %s"
,
k
ind
)
return
fmt
.
Errorf
(
"Unknown profile kind provided: %s"
,
profileK
ind
)
}
outfilePath
:=
path
.
Join
(
getProfilesDirectoryPath
(),
profilePrefix
+
profileBaseName
+
".pdf"
)
outfile
,
err
:=
os
.
Create
(
outfilePath
)
...
...
@@ -124,67 +153,53 @@ func gatherProfileOfKind(profileBaseName, kind string) error {
// finish before the parent goroutine itself finishes, we accept a sync.WaitGroup
// argument in these functions. Typically you would use the following pattern:
//
// func TestFoo
Bar
() {
// func TestFoo() {
// var wg sync.WaitGroup
// wg.Add(3)
// go framework.Gather
ApiserverCPUProfile(&wg, "doing_foo"
)
// go framework.Gather
ApiserverMemoryProfile(&wg, "doing_foo"
)
// go framework.Gather
CPUProfile("kube-apiserver", "before_foo", &wg
)
// go framework.Gather
MemoryProfile("kube-apiserver", "before_foo", &wg
)
// <<<< some code doing foo >>>>>>
// go framework.GatherApiserverCPUProfile(&wg, "doing_bar")
// <<<< some code doing bar >>>>>>
// go framework.GatherCPUProfile("kube-scheduler", "after_foo", &wg)
// wg.Wait()
// }
//
// If you do not wish to exercise the waiting logic, pass a nil value for the
// waitgroup argument instead. However, then you would be responsible for ensuring
// that the function finishes.
// that the function finishes. There's also a polling-based gatherer utility for
// CPU profiles available below.
func
Gather
ApiserverCPUProfile
(
wg
*
sync
.
WaitGroup
,
profileBaseName
string
)
{
Gather
ApiserverCPUProfileForNSeconds
(
wg
,
profileBaseName
,
DefaultCPUProfileSeconds
)
func
Gather
CPUProfile
(
componentName
string
,
profileBaseName
string
,
wg
*
sync
.
WaitGroup
)
{
Gather
CPUProfileForSeconds
(
componentName
,
profileBaseName
,
DefaultCPUProfileSeconds
,
wg
)
}
func
Gather
ApiserverCPUProfileForNSeconds
(
wg
*
sync
.
WaitGroup
,
profileBaseName
string
,
n
int
)
{
func
Gather
CPUProfileForSeconds
(
componentName
string
,
profileBaseName
string
,
seconds
int
,
wg
*
sync
.
WaitGroup
)
{
if
wg
!=
nil
{
defer
wg
.
Done
()
}
if
err
:=
checkProfileGatheringPrerequisites
();
err
!=
nil
{
Logf
(
"Profile gathering pre-requisite failed: %v"
,
err
)
return
}
if
profileBaseName
==
""
{
profileBaseName
=
time
.
Now
()
.
Format
(
time
.
RFC3339
)
}
if
err
:=
gatherProfileOfKind
(
profileBaseName
,
fmt
.
Sprintf
(
"profile?seconds=%v"
,
n
));
err
!=
nil
{
Logf
(
"Failed to gather apiserver CPU profile: %v"
,
err
)
if
err
:=
gatherProfile
(
componentName
,
profileBaseName
,
fmt
.
Sprintf
(
"profile?seconds=%v"
,
seconds
));
err
!=
nil
{
Logf
(
"Failed to gather %v CPU profile: %v"
,
componentName
,
err
)
}
}
func
Gather
ApiserverMemoryProfile
(
wg
*
sync
.
WaitGroup
,
profileBaseName
string
)
{
func
Gather
MemoryProfile
(
componentName
string
,
profileBaseName
string
,
wg
*
sync
.
WaitGroup
)
{
if
wg
!=
nil
{
defer
wg
.
Done
()
}
if
err
:=
checkProfileGatheringPrerequisites
();
err
!=
nil
{
Logf
(
"Profile gathering pre-requisite failed: %v"
,
err
)
return
}
if
profileBaseName
==
""
{
profileBaseName
=
time
.
Now
()
.
Format
(
time
.
RFC3339
)
}
if
err
:=
gatherProfileOfKind
(
profileBaseName
,
"heap"
);
err
!=
nil
{
Logf
(
"Failed to gather apiserver memory profile: %v"
,
err
)
if
err
:=
gatherProfile
(
componentName
,
profileBaseName
,
"heap"
);
err
!=
nil
{
Logf
(
"Failed to gather %v memory profile: %v"
,
componentName
,
err
)
}
}
// Start
ApiserverCPUProfileGatherer is a polling-based gatherer of the apiserver's
//
CPU profile. It takes the delay
b/w consecutive gatherings as an argument and
// Start
CPUProfileGatherer performs polling-based gathering of the component's CPU
//
profile. It takes the interval
b/w consecutive gatherings as an argument and
// starts the gathering goroutine. To stop the gatherer, close the returned channel.
func
Start
ApiserverCPUProfileGatherer
(
delay
time
.
Duration
)
chan
struct
{}
{
func
Start
CPUProfileGatherer
(
componentName
string
,
profileBaseName
string
,
interval
time
.
Duration
)
chan
struct
{}
{
stopCh
:=
make
(
chan
struct
{})
go
func
()
{
for
{
select
{
case
<-
time
.
After
(
delay
)
:
Gather
ApiserverCPUProfile
(
nil
,
""
)
case
<-
time
.
After
(
interval
)
:
Gather
CPUProfile
(
componentName
,
profileBaseName
+
"_"
+
time
.
Now
()
.
Format
(
time
.
RFC3339
),
nil
)
case
<-
stopCh
:
return
}
...
...
test/e2e/scalability/density.go
View file @
457548ef
...
...
@@ -388,7 +388,7 @@ var _ = SIGDescribe("Density", func() {
close
(
profileGathererStopCh
)
wg
:=
sync
.
WaitGroup
{}
wg
.
Add
(
1
)
framework
.
Gather
ApiserverMemoryProfile
(
&
wg
,
"density"
)
framework
.
Gather
MemoryProfile
(
"kube-apiserver"
,
"density"
,
&
wg
)
wg
.
Wait
()
saturationThreshold
:=
time
.
Duration
((
totalPods
/
MinPodsPerSecondThroughput
))
*
time
.
Second
...
...
@@ -487,7 +487,7 @@ var _ = SIGDescribe("Density", func() {
// Start apiserver CPU profile gatherer with frequency based on cluster size.
profileGatheringDelay
:=
time
.
Duration
(
5
+
nodeCount
/
100
)
*
time
.
Minute
profileGathererStopCh
=
framework
.
Start
ApiserverCPUProfileGatherer
(
profileGatheringDelay
)
profileGathererStopCh
=
framework
.
Start
CPUProfileGatherer
(
"kube-apiserver"
,
"density"
,
profileGatheringDelay
)
})
type
Density
struct
{
...
...
test/e2e/scalability/load.go
View file @
457548ef
...
...
@@ -106,7 +106,7 @@ var _ = SIGDescribe("Load capacity", func() {
close
(
profileGathererStopCh
)
wg
:=
sync
.
WaitGroup
{}
wg
.
Add
(
1
)
framework
.
Gather
ApiserverMemoryProfile
(
&
wg
,
"load"
)
framework
.
Gather
MemoryProfile
(
"kube-apiserver"
,
"load"
,
&
wg
)
wg
.
Wait
()
// Verify latency metrics
...
...
@@ -159,7 +159,7 @@ var _ = SIGDescribe("Load capacity", func() {
// Start apiserver CPU profile gatherer with frequency based on cluster size.
profileGatheringDelay
:=
time
.
Duration
(
5
+
nodeCount
/
100
)
*
time
.
Minute
profileGathererStopCh
=
framework
.
Start
ApiserverCPUProfileGatherer
(
profileGatheringDelay
)
profileGathererStopCh
=
framework
.
Start
CPUProfileGatherer
(
"kube-apiserver"
,
"load"
,
profileGatheringDelay
)
})
type
Load
struct
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment