Skip to content
This repository has been archived by the owner on Apr 23, 2024. It is now read-only.

Commit

Permalink
bench: add --profile argument (#39)
Browse files Browse the repository at this point in the history
`--profile` enabled KPHP benchmarks profiling.
  • Loading branch information
quasilyte authored Sep 9, 2022
1 parent e59ad6f commit 997d2ff
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 27 deletions.
2 changes: 2 additions & 0 deletions cmd/ktest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ func cmdBench(args []string) error {
`comma separated list of additional kphp include-dirs`)
fs.StringVar(&conf.RunFilter, "run", ".*",
`regexp that selects the benchmarks to run`)
fs.StringVar(&conf.ProfileDir, "profile", "",
`write mem+cpu profiles to the specified folder; profiling is disabled by default`)
fs.BoolVar(&conf.DisableAutoloadForKPHP, "disable-kphp-autoload", envBool("KTEST_DISABLE_KPHP_AUTOLOAD", false),
`disables autoload for KPHP`)
fs.BoolVar(&conf.TeamcityOutput, "teamcity", false,
Expand Down
2 changes: 2 additions & 0 deletions internal/bench/bench.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ type RunConfig struct {
Preload string
RunFilter string

ProfileDir string

KphpCommand string
PhpCommand string

Expand Down
88 changes: 68 additions & 20 deletions internal/bench/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ type runner struct {

logger *teamcity.Logger

buildDir string
buildDir string
profilerPrefix string
}

type benchFile struct {
Expand Down Expand Up @@ -99,6 +100,7 @@ func (r *runner) Run() error {
{"sort bench files", r.stepSortBenchFiles},
{"generate bench main", r.stepGenerateBenchMain},
{"run bench", r.stepRunBench},
{"move profiles", r.moveProfiles},
}

for _, step := range steps {
Expand Down Expand Up @@ -159,6 +161,13 @@ func (r *runner) stepPrepareTempBuildDir() error {
r.buildDir = tempDir
r.debugf("temp build dir: %q", tempDir)

if r.conf.ProfileDir != "" {
r.profilerPrefix = filepath.Join(r.buildDir, "profiles", "ktest")
if err := fileutil.MkdirAll(filepath.Dir(r.profilerPrefix)); err != nil {
return err
}
}

links := []string{
"vendor",
"composer.json",
Expand Down Expand Up @@ -267,18 +276,19 @@ func (r *runner) stepGenerateBenchMain() error {
for _, f := range r.benchFiles {
var generated bytes.Buffer
templateData := map[string]interface{}{
"BenchFilename": f.fullName,
"BenchClassName": f.info.ClassName,
"BenchClassFQN": f.info.ClassFQN,
"BenchMethods": f.info.BenchMethods,
"BenchQN": fmt.Sprintf("php_qn://%s::%s::", f.fullName, f.info.ClassFQN),
"Unroll": make([]struct{}, 20),
"MinTries": 20,
"IterationsRate": 100000000,
"Count": r.conf.Count,
"Teamcity": r.conf.TeamcityOutput,
"OnlyPhpAutoload": r.conf.DisableAutoloadForKPHP,
"Benchmem": r.conf.Benchmem, // always false for PHP at the moment
"ProfilingEnabled": r.conf.ProfileDir != "",
"BenchFilename": f.fullName,
"BenchClassName": f.info.ClassName,
"BenchClassFQN": f.info.ClassFQN,
"BenchMethods": f.info.BenchMethods,
"BenchQN": fmt.Sprintf("php_qn://%s::%s::", f.fullName, f.info.ClassFQN),
"Unroll": make([]struct{}, 20),
"MinTries": 20,
"IterationsRate": 100000000,
"Count": r.conf.Count,
"Teamcity": r.conf.TeamcityOutput,
"OnlyPhpAutoload": r.conf.DisableAutoloadForKPHP,
"Benchmem": r.conf.Benchmem, // always false for PHP at the moment
}
if r.conf.ComposerRoot != "" {
templateData["Bootstrap"] = filepath.Join(r.conf.ComposerRoot, "vendor", "autoload.php")
Expand Down Expand Up @@ -341,8 +351,15 @@ function __bench_main(int $count) {
}
{{range $bench := $.BenchMethods}}
/** @param {{$.BenchClassFQN}} $bench */
function __bench_{{$bench.Name}}_wrapper($bench) {
/**
* @param {{$.BenchClassFQN}} $bench
*
* {{if $.ProfilingEnabled}}
* @kphp-profile
* @kphp-profile-allow-inline
* {{end}}
*/
function _{{$bench.Name}}($bench) {
while (false) {
break;
if (false) {}
Expand Down Expand Up @@ -376,7 +393,7 @@ function __bench_{{$bench.Name}}(int $count) {
while ($i < $max_tries) {
$start = hrtime(true);
{{ range $.Unroll}}
__bench_{{$bench.Name}}_wrapper($bench);
_{{$bench.Name}}($bench);
{{- end}}
$time_total += hrtime(true) - $start;
$i += {{len $.Unroll}};
Expand Down Expand Up @@ -450,6 +467,7 @@ func (r *runner) stepRunBench() error {
}

buildResult, err := kphpscript.Build(kphpscript.BuildConfig{
ProfilingEnabled: r.conf.ProfileDir != "",
KPHPCommand: r.conf.KphpCommand,
Script: mainFilename,
ComposerRoot: r.conf.ComposerRoot,
Expand All @@ -466,10 +484,11 @@ func (r *runner) stepRunBench() error {
timeTotal := time.Duration(0)
for _, m := range f.info.BenchMethods {
runResult, err := kphpscript.Run(kphpscript.RunConfig{
Executable: buildResult.Executable,
Workdir: r.buildDir,
ScriptArgs: []string{m.Name},
Stderr: r.conf.Output,
ProfilerPrefix: r.profilerPrefix,
Executable: buildResult.Executable,
Workdir: r.buildDir,
ScriptArgs: []string{m.Name},
Stderr: r.conf.Output,
})
timeTotal += runResult.Time
if err != nil {
Expand All @@ -485,3 +504,32 @@ func (r *runner) stepRunBench() error {

return nil
}

func (r *runner) moveProfiles() error {
if r.profilerPrefix == "" {
return nil
}
if err := fileutil.MkdirAll(r.conf.ProfileDir); err != nil {
return err
}
profilesDir := filepath.Dir(r.profilerPrefix)
entries, err := os.ReadDir(profilesDir)
if err != nil {
return err
}
re := regexp.MustCompile(`\.[A-F0-9]+\.\d+$`)
for _, e := range entries {
oldName := filepath.Join(profilesDir, e.Name())
name := strings.TrimPrefix(e.Name(), "ktest._")
name = re.ReplaceAllString(name, "")
newName := filepath.Join(r.conf.ProfileDir, name+".callgrind")
data, err := os.ReadFile(oldName)
if err != nil {
return err
}
if err := fileutil.WriteFile(newName, data); err != nil {
return err
}
}
return nil
}
22 changes: 15 additions & 7 deletions internal/kphpscript/kphpscript.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
)

type BuildConfig struct {
ProfilingEnabled bool
KPHPCommand string
Script string
ComposerRoot string
Expand All @@ -24,11 +25,12 @@ type BuildResult struct {
}

type RunConfig struct {
Executable string
Workdir string
ScriptArgs []string
Stdout io.Writer
Stderr io.Writer
ProfilerPrefix string
Executable string
Workdir string
ScriptArgs []string
Stdout io.Writer
Stderr io.Writer
}

type RunResult struct {
Expand All @@ -42,6 +44,9 @@ func Build(config BuildConfig) (*BuildResult, error) {
"--mode", "cli",
"--destination-directory", config.OutputDir,
}
if config.ProfilingEnabled {
args = append(args, "--profiler", "1")
}
if config.ComposerRoot != "" {
args = append(args, "--composer-root", config.ComposerRoot)
}
Expand All @@ -64,8 +69,11 @@ func Build(config BuildConfig) (*BuildResult, error) {
}

func Run(config RunConfig) (*RunResult, error) {
args := []string{"--Xkphp-options", "--disable-sql"}
args = append(args, config.ScriptArgs...)
args := append([]string{}, config.ScriptArgs...)
args = append(args, "--Xkphp-options", "--disable-sql")
if config.ProfilerPrefix != "" {
args = append(args, "--profiler-log-prefix", config.ProfilerPrefix)
}
runCommand := exec.Command(config.Executable, args...)
runCommand.Dir = config.Workdir
var stdout bytes.Buffer
Expand Down

0 comments on commit 997d2ff

Please sign in to comment.