1 /*
<lambda>null2  * Copyright 2017 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package trebuchet.model.fragments
18 
19 import trebuchet.model.InvalidId
20 import trebuchet.model.hasCount
21 
22 class ProcessModelFragment(id: Int, var name: String? = null,
23                            private var hasIdCb: ((trebuchet.model.fragments.ProcessModelFragment) -> Unit)? = null) {
24     private var _id: Int = id
25     var id: Int
26         get() = _id
27         set(value) {
28             _id = value
29             if (_id != InvalidId) {
30                 hasIdCb?.invoke(this)
31                 hasIdCb = null
32             }
33         }
34 
35     private val _threads = mutableMapOf<Int, ThreadModelFragment>()
36     private val _counters = mutableMapOf<String, CounterFragment>()
37 
38     val threads: Collection<ThreadModelFragment> get() = _threads.values
39     val counters: Map<String, CounterFragment> get() = _counters
40     val asyncSlicesBuilder = AsyncSlicesBuilder()
41     val asyncSlices: List<AsyncSlice> get() {
42         if (asyncSlicesBuilder.openSlices.isNotEmpty()) {
43             throw IllegalStateException("AsyncSlicesBuilder has open slices, not finished");
44         }
45         return asyncSlicesBuilder.asyncSlices
46     }
47 
48     fun threadFor(pid: Int, name: String? = null): ThreadModelFragment {
49         var thread = _threads[pid]
50         if (thread == null) {
51             thread = ThreadModelFragment(pid, this, name)
52             _threads.put(pid, thread)
53         } else {
54             thread.hint(name = name)
55         }
56         return thread
57     }
58 
59     fun addCounterSample(name: String, timestamp: Double, value: Long) {
60         _counters.getOrPut(name, { CounterFragment(name) }).events.add(timestamp hasCount value)
61     }
62 
63     fun merge(other: trebuchet.model.fragments.ProcessModelFragment) {
64         if (other === this) return
65         if (id != -1 && id != other.id) {
66             throw IllegalArgumentException("Process ID mismatch")
67         }
68         hint(name = other.name)
69         other._threads.forEach { (key, value) ->
70             if (_threads.put(key, value) != null) {
71                 throw IllegalStateException("Unable to merge threads of the same ID $key")
72             }
73             value.process = this
74         }
75         other._counters.forEach { (key, value) ->
76             val existing = _counters.put(key, value)
77             if (existing != null) {
78                 _counters[key]!!.events.addAll(existing.events)
79             }
80         }
81     }
82 
83     fun hint(id: Int = InvalidId, name: String? = null) {
84         if (this.id == InvalidId) this.id = id
85         if (this.name == null) this.name = name
86     }
87 }