1// Copyright 2018 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package tracer
16
17import (
18	"android/soong/ui/status"
19	"time"
20)
21
22func (t *tracerImpl) StatusTracer() status.StatusOutput {
23	return &statusOutput{
24		tracer: t,
25
26		running: map[*status.Action]actionStatus{},
27	}
28}
29
30type actionStatus struct {
31	cpu   int
32	start time.Time
33}
34
35type statusOutput struct {
36	tracer *tracerImpl
37
38	cpus    []bool
39	running map[*status.Action]actionStatus
40}
41
42func (s *statusOutput) StartAction(action *status.Action, counts status.Counts) {
43	cpu := -1
44	for i, busy := range s.cpus {
45		if !busy {
46			cpu = i
47			s.cpus[i] = true
48			break
49		}
50	}
51
52	if cpu == -1 {
53		cpu = len(s.cpus)
54		s.cpus = append(s.cpus, true)
55	}
56
57	s.running[action] = actionStatus{
58		cpu:   cpu,
59		start: time.Now(),
60	}
61}
62
63func (s *statusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
64	start, ok := s.running[result.Action]
65	if !ok {
66		return
67	}
68	delete(s.running, result.Action)
69	s.cpus[start.cpu] = false
70
71	str := result.Action.Description
72	if len(result.Action.Outputs) > 0 {
73		str = result.Action.Outputs[0]
74	}
75
76	s.tracer.writeEvent(&viewerEvent{
77		Name:  str,
78		Phase: "X",
79		Time:  uint64(start.start.UnixNano()) / 1000,
80		Dur:   uint64(time.Since(start.start).Nanoseconds()) / 1000,
81		Pid:   1,
82		Tid:   uint64(start.cpu),
83		Arg: &statsArg{
84			UserTime:                   result.Stats.UserTime,
85			SystemTime:                 result.Stats.SystemTime,
86			MaxRssKB:                   result.Stats.MaxRssKB,
87			MinorPageFaults:            result.Stats.MinorPageFaults,
88			MajorPageFaults:            result.Stats.MajorPageFaults,
89			IOInputKB:                  result.Stats.IOInputKB,
90			IOOutputKB:                 result.Stats.IOOutputKB,
91			VoluntaryContextSwitches:   result.Stats.VoluntaryContextSwitches,
92			InvoluntaryContextSwitches: result.Stats.InvoluntaryContextSwitches,
93		},
94	})
95}
96
97type statsArg struct {
98	UserTime                   uint32 `json:"user_time"`
99	SystemTime                 uint32 `json:"system_time_ms"`
100	MaxRssKB                   uint64 `json:"max_rss_kb"`
101	MinorPageFaults            uint64 `json:"minor_page_faults"`
102	MajorPageFaults            uint64 `json:"major_page_faults"`
103	IOInputKB                  uint64 `json:"io_input_kb"`
104	IOOutputKB                 uint64 `json:"io_output_kb"`
105	VoluntaryContextSwitches   uint64 `json:"voluntary_context_switches"`
106	InvoluntaryContextSwitches uint64 `json:"involuntary_context_switches"`
107}
108
109func (s *statusOutput) Flush()                                        {}
110func (s *statusOutput) Message(level status.MsgLevel, message string) {}
111
112func (s *statusOutput) Write(p []byte) (int, error) {
113	// Discard writes
114	return len(p), nil
115}
116