// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto2";

package soong_build_metrics;
option go_package = "android/soong/ui/metrics/metrics_proto";

message MetricsBase {
  // Timestamp generated when the build starts.
  optional int64 build_date_timestamp = 1;

  // It is usually used to specify the branch name [and release candidate].
  optional string build_id  = 2;

  // The platform version codename, eg. P, Q, REL.
  optional string platform_version_codename = 3;

  // The target product information, eg. aosp_arm.
  optional string target_product = 4;

  enum BuildVariant {
    USER = 0;
    USERDEBUG = 1;
    ENG = 2;
  }
  // The target build variant information, eg. eng.
  optional BuildVariant target_build_variant = 5 [default = ENG];

  enum Arch {
    UNKNOWN = 0;
    ARM = 1;
    ARM64 = 2;
    X86 = 3;
    X86_64 = 4;
  }
  // The target arch information, eg. arm.
  optional Arch target_arch = 6 [default = UNKNOWN];

  // The target arch variant information, eg. armv7-a-neon.
  optional string target_arch_variant = 7;

  // The target cpu variant information, eg. generic.
  optional string target_cpu_variant = 8;

  // The host arch information, eg. x86_64.
  optional Arch host_arch = 9 [default = UNKNOWN];

  // The host 2nd arch information, eg. x86.
  optional Arch host_2nd_arch = 10 [default = UNKNOWN];

  // The host os information, eg. linux.
  optional string host_os = 11;

  // The host os extra information, eg. Linux-4.17.0-3rodete2-amd64-x86_64-Debian-GNU.
  optional string host_os_extra = 12;

  // The host cross os information, eg. windows.
  optional string host_cross_os = 13;

  // The host cross arch information, eg. x86.
  optional string host_cross_arch = 14;

  // The host cross 2nd arch information, eg. x86_64.
  optional string host_cross_2nd_arch = 15;

  // The directory for generated built artifacts installation, eg. out.
  optional string out_dir = 16;

  // The metrics for calling various tools (microfactory) before Soong_UI starts.
  repeated PerfInfo setup_tools = 17;

  // The metrics for calling Kati by multiple times.
  repeated PerfInfo kati_runs = 18;

  // The metrics for calling Soong.
  repeated PerfInfo soong_runs = 19;

  // The metrics for calling Ninja.
  repeated PerfInfo ninja_runs = 20;

  // The metrics for the whole build
  optional PerfInfo total = 21;

  // Deprecated because instead of embedding in a MetricsBase, we keep
  // SoongBuildMetrics in its own file
  optional SoongBuildMetrics soong_build_metrics = 22 [deprecated=true];

  optional BuildConfig build_config = 23;

  // The hostname of the machine.
  optional string hostname = 24;

  // The system resource information such as total physical memory.
  optional SystemResourceInfo system_resource_info = 25;

  // The build command that the user entered to the build system.
  optional string build_command = 26;

  // The metrics for calling Bazel.
  repeated PerfInfo bazel_runs = 27;

  // The metrics of the experiment config fetcher
  optional ExpConfigFetcher exp_config_fetcher = 28;

  // Whether the build exited with a panic or non-zero exit code, includes both
  // non-zero exits of recorded phases and non-recorded phases of the build.
  optional bool non_zero_exit = 29;

  // The error message due to a non-zero exit _only_ if it did not occur in a
  // recorded phase of the build.
  optional string error_message = 30;

  // The Git Manifest for the user's branch.
  optional string manifest_url = 31;

  // The branch on which the build occurred.
  // Example: refs/heads/master
  optional string branch = 32;

  // The metric of critical path in build
  optional CriticalPathInfo critical_path_info = 33;

  // Environment variables that have changed value since the previous build,
  // which were responsible for retriggering build analysis.
  // Note that not all changed environment variables result in analysis retriggering.
  // If there was no previous build, this list will be empty.
  repeated string changed_environment_variable = 34;

  // Metrics related to optimized builds.
  optional OptimizedBuildMetrics optimized_build_metrics = 35;
}

message BuildConfig {
  enum NinjaWeightListSource {
    NOT_USED = 0;
    NINJA_LOG = 1;
    EVENLY_DISTRIBUTED = 2;
    EXTERNAL_FILE = 3;
    HINT_FROM_SOONG = 4;
  }

  optional bool use_goma = 1;

  optional bool use_rbe = 2;

  optional bool force_use_goma = 3;

  // Whether the Bazel is acting as the Ninja executor for this build.
  optional bool bazel_as_ninja = 4;

  // Whether build is occurring in a mixed build mode, where Bazel maintains the
  // definition and build of some modules in cooperation with Soong.
  optional bool bazel_mixed_build = 5;

  // These are the targets soong passes to ninja, these targets include special
  // targets such as droid as well as the regular build targets.
  repeated string targets = 6;

  // Whether the user explicitly disabled bazel mixed builds for this build.
  optional bool force_disable_bazel_mixed_build = 7;

  // NOT_USED - ninja doesn't use weight list.
  // NINJA_LOG - ninja uses weight list based on previous builds by ninja log
  // EVENLY_DISTRIBUTED - ninja thinks every task has the same weight.
  // EXTERNAL_FILE - ninja uses an external custom weight list
  // HINT_FROM_SOONG - ninja uses a prioritized module list from Soong
  optional NinjaWeightListSource ninja_weight_list_source = 8 [default = NOT_USED];
}

message SystemResourceInfo {
  // The total physical memory in bytes.
  optional uint64 total_physical_memory = 1;

  // The total of available cores for building
  optional int32 available_cpus = 2;

  // Information about the machine's CPU(s).
  optional SystemCpuInfo cpu_info = 3;

  // Information about the machine's memory.
  optional SystemMemInfo mem_info = 4;
}

message SystemCpuInfo {
  // The vendor id
  optional string vendor_id = 1;

  // The model name
  optional string model_name = 2;

  // The number of CPU cores
  optional int32 cpu_cores = 3;

  // The CPU flags
  optional string flags = 4;
}

message SystemMemInfo {
  // The total system memory
  optional uint64 mem_total = 1;

  // The free system memory
  optional uint64 mem_free = 2;

  // The available system memory
  optional uint64 mem_available = 3;
}

message PerfInfo {
  // The description for the phase/action/part while the tool running.
  optional string description = 1;

  // The name for the running phase/action/part.
  optional string name = 2;

  // The absolute start time.
  // The number of nanoseconds elapsed since January 1, 1970 UTC.
  optional uint64 start_time = 3;

  // The real running time.
  // The number of nanoseconds elapsed since start_time.
  optional uint64 real_time = 4;

  // The number of MB for memory use (deprecated as it is too generic).
  optional uint64 memory_use = 5 [deprecated=true];

  // The resource information of each executed process.
  repeated ProcessResourceInfo processes_resource_info = 6;

  // Whether the phase of tool running exited with a panic or non-zero exit
  // code.
  optional bool non_zero_exit = 7;

  // The error message, if any, due to a non-zero exit.
  optional string error_message = 8;
}

message PerfCounters {
  // The timestamp of these counters in nanoseconds.
  optional uint64 time = 1;

  // A list of counter names and values.
  repeated PerfCounterGroup groups = 2;
}

message PerfCounterGroup {
  // The name of this counter group (e.g. "cpu" or "memory")
  optional string name = 1;

  // The counters in this group
  repeated PerfCounter counters = 2;
}

message PerfCounter {
  // The name of this counter.
  optional string name = 1;

  // The value of this counter.
  optional int64 value = 2;
}

message ProcessResourceInfo {
  // The name of the process for identification.
  optional string name = 1;

  // The amount of time spent executing in user space in microseconds.
  optional uint64 user_time_micros = 2;

  // The amount of time spent executing in kernel mode in microseconds.
  optional uint64 system_time_micros = 3;

  // The maximum resident set size memory used in kilobytes.
  optional uint64 max_rss_kb = 4;

  // The number of minor page faults serviced without any I/O activity.
  optional uint64 minor_page_faults = 5;

  // The number of major page faults serviced that required I/O activity.
  optional uint64 major_page_faults = 6;

  // Total IO input in kilobytes.
  optional uint64 io_input_kb= 7;

  // Total IO output in kilobytes.
  optional uint64 io_output_kb = 8;

  // The number of voluntary context switches
  optional uint64 voluntary_context_switches = 9;

  // The number of involuntary context switches
  optional uint64 involuntary_context_switches = 10;
}

message ModuleTypeInfo {
  enum BuildSystem {
    UNKNOWN = 0;
    SOONG = 1;
    MAKE = 2;
  }
  // The build system, e.g. Soong or Make.
  optional BuildSystem build_system = 1 [default = UNKNOWN];

  // The module type, e.g. java_library, cc_binary, and etc.
  optional string module_type = 2;

  // The number of logical modules.
  optional uint32 num_of_modules = 3;
}

message CriticalUserJourneyMetrics {
  // The name of a critical user journey test.
  optional string name = 1;

  // The metrics produced when running the critical user journey test.
  optional MetricsBase metrics = 2;
}

message CriticalUserJourneysMetrics {
  // A set of metrics from a run of the critical user journey tests.
  repeated CriticalUserJourneyMetrics cujs = 1;
}

message SoongBuildMetrics {
  // The number of modules handled by soong_build.
  optional uint32 modules = 1;

  // The total number of variants handled by soong_build.
  optional uint32 variants = 2;

  // The total number of allocations in soong_build.
  optional uint64 total_alloc_count = 3;

  // The total size of allocations in soong_build in bytes.
  optional uint64 total_alloc_size = 4;

  // The approximate maximum size of the heap in soong_build in bytes.
  optional uint64 max_heap_size = 5;

  // Runtime metrics for soong_build execution.
  repeated PerfInfo events = 6;

  // Mixed Builds information
  optional MixedBuildsInfo mixed_builds_info = 7;

  // Performance during for soong_build execution.
  repeated PerfCounters perf_counters = 8;
}

message ExpConfigFetcher {
  enum ConfigStatus {
    NO_CONFIG = 0;
    CONFIG = 1;
    ERROR = 2;
    MISSING_GCERT = 3;
  }
  // The result of the call to expconfigfetcher
  // NO_CONFIG - Not part of experiment
  // CONFIG - Part of experiment, config copied successfully
  // ERROR - expconfigfetcher failed
  optional ConfigStatus status = 1;

  // The output config filename
  optional string filename = 2;

  // Time, in microseconds, taken by the expconfigfetcher
  optional uint64 micros = 3;
}

message MixedBuildsInfo{
  // Modules may be listed below as both enabled for Mixed Builds
  // and disabled for Mixed Builds. This implies that some variants
  // of the module are handled by Bazel in a Mixed Build, and other
  // variants of the same module are handled by Soong.

  // Modules that are enabled for Mixed Builds.
  repeated string mixed_build_enabled_modules = 1;

  // Modules that are not currently eligible to be handled
  // by Bazel in a Mixed Build.
  // Note that not all modules exempt from Bazel handling are
  // listed. This list includes only modules which are of a
  // Mixed-Build supported module type but are nevertheless not
  // handled by Bazel. This may occur due to being present in
  // the mixed build denylist, or as part of an unsupported
  // mixed build variant type such as Windows.

  // Modules that are not enabled for MixedBuilds
  repeated string mixed_build_disabled_modules = 2;
}

// CriticalPathInfo contains critical path nodes's information.
// A critical path is a path determining the minimum time needed for the whole build given perfect parallelism.
message CriticalPathInfo {
  // Real time which the build system spent in microseconds
  optional uint64 elapsed_time_micros = 1;
  // The sum of execution time of the longest path from leave to the root in microseconds
  optional uint64 critical_path_time_micros = 2;
  // Detailed job information in a critical path.
  repeated JobInfo critical_path = 4;
  // Detailed job information for long running jobs (>30 seconds). These may or may not also be on a critical path.
  repeated JobInfo long_running_jobs = 5;
}

message JobInfo {
  // Real time which a job spent in microseconds
  optional uint64 elapsed_time_micros = 1;
  // Description of a job
  optional string job_description = 2;
}

message OptimizedBuildMetrics {
  // The total time spent analyzing what/how to optimize everything.
  optional PerfInfo analysis_perf = 1;
  // The total time spent packaging artifacts.
  optional PerfInfo packaging_perf = 2;
  // Information for a single target (e.g. general-tests).
  repeated TargetOptimizationResult target_result = 3;

  message TargetOptimizationResult {
    // Target name (e.g. general-tests).
    optional string name = 1;
    // Whether or not this target was optimized.
    optional bool optimized = 2;
    // Reasoning for why the target wasn't optimized if it wasn't
    optional string optimization_rationale = 3;
    // Time spent packaging this specific target (if it was optimized).
    optional PerfInfo packaging_perf = 4;
    // Information for each different artifact produced by this target (if it
    // was optimized).
    repeated OutputArtifact output_artifact = 5;

    message OutputArtifact {
      // Artifact file name (e.g. general-tests.zip)
      optional string name = 1;
      // Size of the file.
      optional int64 size = 2;
      // Lists of modules packaged into this artifact.
      repeated string included_modules = 3;
    }
  }
}
