Как определить время и профилировать * раздел * программы в golang с помощью `go test`?

#go #profiling

#Вперед #профилирование

Вопрос:

Вопрос: Как определить время и профилировать раздел программы в golang с помощью go test ?

Пример использования: у меня есть алгоритм параллельной обработки массовых операций для дерева B . Я использую go test для профилирования и сравнения с другими базовыми алгоритмами (сериализованная версия, пессимистическая блокировка и т.д.). Для настройки тестового примера я создам дерево B с 1 МЛН записей и создам список из 1 млн операций, затем я начну фактическое тестирование BulkProcess этих операций.

 func TestInputTreeM1e6N1e6(*testing.T) {
    M := 1000000

    //Test Preparation 1: Setup the tree
    tree := NewTree(cmp)
    file1name := "InitalTree_10000000.txt"

    testF1, err := os.Open(file1name)
    if err != nil {
        panic(err)
    }
    defer testF1.Close()

    nums, _ := ReadInts(testF1)
    for i, num := range nums {
        if i == M {
            break
        }
        tree.Set(Int(num), Int(1))
    }


    fmt.Println("Tree initialized")

    //Test Prepration 2: Initialize operations
    N := 1000000 
    inputs := make([]SearchPair, N)

    file2name := "Operations_10000000.txt"
    testF2, err := os.Open(file2name)
    if err != nil {
        panic(err)
    }
    defer testF2.Close()

    var opt string
    var num int
    var input SearchPair
    for i:=0; i < N; i  {

        fmt.Fscanf(testF2, "%s %d", amp;opt, amp;num)

        switch opt {
        case "DEL":
            input = SearchPair{
                opt: DEL,   //Operation to be applied
                k: Int(num),    //k to be operated upon
                v: Int(0),
            }
        case "PUT":
            input = SearchPair{
                opt: PUT,   //Operation to be applied
                k: Int(num),    //k to be operated upon
                v: Int(-1),
            }
        case "SET":
            input = SearchPair{
                opt: SET,   //Operation to be applied
                k: Int(num),    //k to be operated upon
                v: Int(2),
            }
        }

        inputs[i] = input
    }

    //Start actual testing
    fmt.Println("Start processing...")
    tree.BulkProcess(inputs)
    fmt.Println("Done")

}
  

Проблема: я использую go test -v -cpuprofile cpu.out -memprofile mem.out для профилирования BulkProcess производительности, затем использую go tool pprof --pdf ConcurrentBPlusTree.test mem.out > mgraph.pdf и go tool pprof --pdf ConcurrentBPlusTree.test cpu.out > cgraph.pdf для визуализации результата.

Прямо сейчас go test , похоже, выполняется профилирование всего тестового примера, включая построение дерева и построение операций. Файловый ввод-вывод во время настройки теста доминировал в производительности до такой степени, что я даже не мог видеть, что происходит в моем реальном тестировании.

Кроме того, go test имеет выходные строки, подобные этой

 === RUN   TestInputTreeM1e6N1e6
--- PASS: TestInputTreeM1e6N1e6 (63.36s)
  

Возможно ли настроить таймер так, чтобы он показывал только время, затраченное на массовую обработку, а не на весь случай? Я знаю, что у b *testing.B есть API, такие как b.ResetTimer() и b.StopTimer() . Существует ли аналогичный API для *testing.T , чтобы я мог изменить поведение синхронизации?

Конкретный вопрос

  1. Как я могу использовать go test для профилирования только последних трех строк моего текущего тестового примера?
  2. Как я могу использовать go test для определения времени только для последних трех строк моего текущего тестового примера?

Ответ №1:

Если вы не хотите профилировать всю программу, вы можете запускать и останавливать CPUProfile самостоятельно, используя runtime/pprof пакет:

 f, err := os.Create(profileFileName)
if err != nil {
    log.Fatal("could not create CPU profile: ", err)
}
if err := pprof.StartCPUProfile(f); err != nil {
    log.Fatal("could not start CPU profile: ", err)
}
defer pprof.StopCPUProfile()
  

Комментарии:

1. Возможно ли получить обработчик профиля процессора, f который go test был установлен для меня, чтобы мне нужно было только обернуть определенный раздел с помощью StartCPUProfile(f) и StopCPUProfile() в моем тестовом примере, все еще используя тот же go test CLI?

2. @cookieisaac: нет, потому что go test уже будет запущен профиль процессора, и может быть запущен только один. Однако вы могли бы просто определить свой собственный флаг, т. Е. -testprofile