代码之家  ›  专栏  ›  技术社区  ›  Tim

测量所有目标(包括相关目标)的xcodebuild持续时间

  •  2
  • Tim  · 技术社区  · 7 年前

    有可能测量时间吗 xcodebuild 命令消耗以构建每个不同的目标?

    假设我有一个目标,这取决于一些 cocoapod s: pod1 pod2 . 我使用 xcodebuild . 我可以测量总时间。 我需要测量单独花费在 pod1 pod2 还有我的目标

    我试图从中找到答案 xcodebuild 的输出,但未能这样做。

    提前感谢!

    1 回复  |  直到 7 年前
        1
  •  7
  •   coverback    5 年前

    我最后写了一个习惯 ruby 修改我的每个目标的脚本 xcodeproj Pods.xcodeproj . 此脚本添加了两个 build phase 将目标名称和当前时间戳记录到输出文件中的。一 构建阶段 首先执行,另一个最后执行。稍后,我只是在一个单独的脚本中从另一个时间戳中减去一个时间戳。

    以下是脚本的结果:

    /Users/tryusipov/Desktop/screenshots/Image 2017-11-17 18-23-49.png


    输出文件如下所示(排序后)

    Alamofire end: 1510929112.3409
    Alamofire start: 1510929110.2161
    AlamofireImage end: 1510929113.6925
    AlamofireImage start: 1510929112.5205
    

    输出文件的路径( /a/ci_automation/metrics/performance-metrics/a.txt 在屏幕截图上)无论如何都不是硬编码的。相反,您将其作为 红宝石 脚本如下:

    $ruby prepare-for-target-build-time-profiling.rb ${PWD}/output.txt

    注意,此脚本需要 cocoapods 1.3.1 (也许 1.3 ).


    这是 红宝石 脚本: ruby prepare-for-target-build-time-profiling.rb

    #!/usr/bin/env ruby
    
    require 'xcodeproj'
    require 'cocoapods'
    require 'fileutils'
    
    def inject_build_time_profiling_build_phases(project_path)
        project = Xcodeproj::Project.open(project_path)
    
        log_time_before_build_phase_name = '[Prefix placeholder] Log time before build'.freeze
        log_time_after_build_phase_name = '[Prefix placeholder] Log time after build'.freeze
    
        puts "Patching project at path: #{project_path}"
        puts
        project.targets.each do |target|
            puts "Target: #{target.name}"
    
            first_build_phase = create_leading_build_phase(target, log_time_before_build_phase_name)
            last_build_phase = create_trailing_build_phase(target, log_time_after_build_phase_name)
    
            puts
        end
    
        project.save
    
        puts "Finished patching project at path: #{project_path}"
        puts
    end
    
    def create_leading_build_phase(target, build_phase_name)
        remove_existing_build_phase(target, build_phase_name)
    
        build_phase = create_build_phase(target, build_phase_name)
    
        shift_build_phase_leftwards(target, build_phase)
    
        is_build_phase_leading = true
    
        inject_shell_code_into_build_phase(target, build_phase, is_build_phase_leading)
    
        return build_phase
    end
    
    def create_trailing_build_phase(target, build_phase_name)
        remove_existing_build_phase(target, build_phase_name)
    
        build_phase = create_build_phase(target, build_phase_name)
    
        is_build_phase_leading = false
    
        inject_shell_code_into_build_phase(target, build_phase, is_build_phase_leading)
    
        return build_phase
    end
    
    def remove_existing_build_phase(target, build_phase_name)
        existing_build_phase = target.shell_script_build_phases.find do |build_phase|
            build_phase.name.end_with?(build_phase_name)
            # We use `end_with` instead of `==`, because `cocoapods` adds its `[CP]` prefix to a `build_phase_name`
        end
    
        if !existing_build_phase.nil?
            puts "deleting build phase #{existing_build_phase.name}"
    
            target.build_phases.delete(existing_build_phase)
        end
    end
    
    def create_build_phase(target, build_phase_name)
        puts "creating build phase: #{build_phase_name}"
    
        build_phase = Pod::Installer::UserProjectIntegrator::TargetIntegrator
            .create_or_update_shell_script_build_phase(target, build_phase_name)
    
        return build_phase
    end
    
    def shift_build_phase_leftwards(target, build_phase)
        puts "moving build phase leftwards: #{build_phase.name}"
    
        target.build_phases.unshift(build_phase).uniq! unless target.build_phases.first == build_phase
    end
    
    def inject_shell_code_into_build_phase(target, build_phase, is_build_phase_leading)
        start_or_end = is_build_phase_leading ? "start" : "end"
    
        build_phase.shell_script = <<-SH.strip_heredoc
            timestamp=`echo "scale=4; $(gdate +%s%N/1000000000)" | bc`
            echo "#{target.name} #{start_or_end}: ${timestamp}" >> #{$build_time_logs_output_file}
        SH
    end
    
    def parse_arguments
        $build_time_logs_output_file = ARGV[0]
    
        if $build_time_logs_output_file.to_s.empty? || ! $build_time_logs_output_file.start_with?("/")
            puts "Error: you should pass a full path to a output file as an script's argument. Example:"
            puts "$ruby prepare-for-target-build-time-profiling.rb /path/to/script/output.txt"
            puts
            exit 1
        end
    end
    
    def print_arguments
        puts "Arguments:"
        puts "Output path: #{$build_time_logs_output_file}"
        puts
    end
    
    def clean_up_before_script
        if File.exist?($build_time_logs_output_file)
            FileUtils.rm($build_time_logs_output_file)
        end
    
        build_time_logs_output_folder = File.dirname($build_time_logs_output_file)
        unless File.directory?(build_time_logs_output_folder)
            FileUtils.mkdir_p(build_time_logs_output_folder)
        end
    end
    
    def main 
        parse_arguments
        print_arguments
        clean_up_before_script
        inject_build_time_profiling_build_phases("path/to/project.xcodeproj")
        inject_build_time_profiling_build_phases("path/to/pods/project.xcodeproj")
    end
    
    # arguments:
    $build_time_logs_output_file
    
    main