Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neo
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Labels
Merge Requests
2
Merge Requests
2
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Jobs
Commits
Open sidebar
Kirill Smelkov
neo
Commits
e897a0ab
Commit
e897a0ab
authored
Sep 08, 2017
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
X gmigrate - tool to show number of G migrations between Ms (OS threads)
parent
a62533b1
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
228 additions
and
0 deletions
+228
-0
go/gmigrate.go
go/gmigrate.go
+228
-0
No files found.
go/gmigrate.go
0 → 100644
View file @
e897a0ab
// gmigrate - show number of times G migrates to another M (OS thread).
// usage: `go tool trace -d <trace.out> |gmigrate`
package
main
// +build ignore
import
(
"bufio"
"errors"
"io"
"log"
"fmt"
"os"
"regexp"
"sort"
"strconv"
"strings"
)
// we analyze input stream and take notices on ProcStart and GoStart events.
// when a ProcStart event comes, e.g.
//
// 9782014 ProcStart p=2 g=0 off=133138 thread=5
//
// we remember that a P is currently running on an M (=thread).
//
// when a GoStart event comes, e.g.
//
// 9782310 GoStart p=2 g=33 off=133142 g=33 seq=0
//
// we see that a G is using P to run, and by using previously noted P->M
// relation, conclude G->M relation.
//
// Then for every G noticed we record how much it changes its M.
type
procStart
struct
{
p
int
m
int
// =thread
}
type
goStart
struct
{
g
int
p
int
}
// information about a G
type
gInfo
struct
{
g
int
m
int
// last time was running on this M
nmigrate
int
// how much times migrated between different Ms
}
func
main
()
{
var
pm
=
map
[
int
]
int
{}
// p -> m
var
gg
=
map
[
int
]
*
gInfo
{}
// g -> (m, #migrate)
in
:=
bufio
.
NewReader
(
os
.
Stdin
)
tstart
,
tend
,
tprev
:=
-
1
,
-
1
,
-
1
for
lineno
:=
1
;;
lineno
++
{
bad
:=
func
(
err
error
)
{
log
.
Fatalf
(
"%d: %v"
,
lineno
,
err
)
}
badf
:=
func
(
format
string
,
argv
...
interface
{})
{
bad
(
fmt
.
Errorf
(
format
,
argv
...
))
}
l
,
err
:=
in
.
ReadString
(
'\n'
)
if
err
!=
nil
{
if
err
==
io
.
EOF
{
break
}
bad
(
err
)
}
l
=
l
[
:
len
(
l
)
-
1
]
// strip trailing '\n'
t
,
evname
,
args
,
err
:=
parseLineHeader
(
l
)
if
err
!=
nil
{
bad
(
err
)
}
if
t
<
tprev
{
badf
(
"time monotonity broken"
)
}
tprev
=
t
if
tstart
==
-
1
{
tstart
=
t
}
else
{
tend
=
t
}
switch
evname
{
case
"ProcStart"
:
pstart
,
err
:=
parseProcStart
(
args
)
if
err
!=
nil
{
bad
(
err
)
}
pm
[
pstart
.
p
]
=
pstart
.
m
case
"GoStart"
:
gstart
,
err
:=
parseGoStart
(
args
)
if
err
!=
nil
{
bad
(
err
)
}
m
,
ok
:=
pm
[
gstart
.
p
]
if
!
ok
{
badf
(
"G%d start on P%d, but no matching previous P%d start"
,
gstart
.
g
,
gstart
.
p
,
gstart
.
p
)
}
g
,
seen
:=
gg
[
gstart
.
g
]
if
!
seen
{
gg
[
gstart
.
g
]
=
&
gInfo
{
g
:
gstart
.
g
,
m
:
m
,
nmigrate
:
0
}
break
}
if
g
.
m
!=
m
{
g
.
m
=
m
g
.
nmigrate
++
}
}
}
// all information collected - analyze
gv
:=
make
([]
*
gInfo
,
0
,
len
(
gg
))
for
_
,
g
:=
range
gg
{
gv
=
append
(
gv
,
g
)
}
// order: (nmigrate, g)↓
sort
.
Slice
(
gv
,
func
(
i
,
j
int
)
bool
{
ni
,
nj
:=
gv
[
i
]
.
nmigrate
,
gv
[
j
]
.
nmigrate
return
(
nj
<
ni
)
||
(
nj
==
ni
&&
gv
[
j
]
.
g
<
gv
[
i
]
.
g
)
// reverse
})
fmt
.
Printf
(
"G
\t
N(migrate)
\t
migrate/s
\n
"
)
fmt
.
Printf
(
"-
\t
----------
\t
---------
\n
"
)
for
_
,
g
:=
range
gv
{
fmt
.
Printf
(
"G%d
\t
%8d
\t
%8.1f
\n
"
,
g
.
g
,
g
.
nmigrate
,
float64
(
g
.
nmigrate
)
/
(
float64
(
tend
-
tstart
)
*
1E-9
))
}
}
// "9782014 ProcStart p=2 g=0 off=133138 thread=5"
// ->
// 9782014 "ProcStart" "p=2 g=0 off=133138 thread=5"
func
parseLineHeader
(
l
string
)
(
t
int
,
event
,
args
string
,
err
error
)
{
sp
:=
strings
.
IndexByte
(
l
,
' '
)
if
sp
<
0
{
return
0
,
""
,
""
,
fmt
.
Errorf
(
"parse: invalid timestamp"
)
}
t
,
err
=
strconv
.
Atoi
(
l
[
:
sp
])
if
err
!=
nil
{
return
0
,
""
,
""
,
fmt
.
Errorf
(
"parse: invalid timestamp"
)
}
l
=
l
[
sp
+
1
:
]
sp
=
strings
.
IndexByte
(
l
,
' '
)
if
sp
<
0
{
return
0
,
""
,
""
,
fmt
.
Errorf
(
"parse: invalid event name"
)
}
return
t
,
l
[
:
sp
],
l
[
sp
+
1
:
],
nil
}
// ex: 9782014 ProcStart p=2 g=0 off=133138 thread=5
var
(
pStartArgvRe
=
regexp
.
MustCompile
(
"^p=([^ ]+) g=[^ ]+ off=[^ ]+ thread=([^ ]+)$"
)
pStartArgvErr
=
errors
.
New
(
"ProcStart: argv invalid"
)
)
func
parseProcStart
(
args
string
)
(
procStart
,
error
)
{
argv
:=
pStartArgvRe
.
FindStringSubmatch
(
args
)
if
argv
==
nil
{
return
procStart
{},
pStartArgvErr
}
var
pstart
procStart
var
err
error
pstart
.
p
,
err
=
strconv
.
Atoi
(
argv
[
1
])
if
err
!=
nil
{
return
procStart
{},
pStartArgvErr
}
pstart
.
m
,
err
=
strconv
.
Atoi
(
argv
[
2
])
if
err
!=
nil
{
return
procStart
{},
pStartArgvErr
}
return
pstart
,
nil
}
// ex: 9782310 GoStart p=2 g=33 off=133142 g=33 seq=0
var
(
gStartArgvRe
=
regexp
.
MustCompile
(
"^p=([^ ]+) g=([^ ]+) off=[^ ]+ g=([^ ]+) seq=[^ ]+$"
)
gStartArgvErr
=
errors
.
New
(
"GoStart: argv invalid"
)
)
func
parseGoStart
(
args
string
)
(
goStart
,
error
)
{
argv
:=
gStartArgvRe
.
FindStringSubmatch
(
args
)
if
argv
==
nil
{
return
goStart
{},
gStartArgvErr
}
var
gstart
goStart
var
err
error
gstart
.
p
,
err
=
strconv
.
Atoi
(
argv
[
1
])
if
err
!=
nil
{
return
goStart
{},
gStartArgvErr
}
gstart
.
g
,
err
=
strconv
.
Atoi
(
argv
[
2
])
if
err
!=
nil
{
return
goStart
{},
gStartArgvErr
}
// double-check g is the same
g2
,
err
:=
strconv
.
Atoi
(
argv
[
3
])
if
g2
!=
gstart
.
g
{
log
.
Print
(
"found GoStart with different g"
)
return
goStart
{},
gStartArgvErr
}
return
gstart
,
nil
}
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