2424import com .engflow .bazel .invocation .analyzer .traceeventformat .CounterEvent ;
2525import com .engflow .bazel .invocation .analyzer .traceeventformat .TraceEventFormatConstants ;
2626import com .google .common .annotations .VisibleForTesting ;
27+ import com .google .common .base .Preconditions ;
2728import com .google .common .base .Strings ;
2829import com .google .common .collect .ImmutableList ;
2930import com .google .common .collect .ImmutableMap ;
@@ -78,15 +79,35 @@ public static BazelProfile createFromPath(String path) throws IllegalArgumentExc
7879
7980 public static BazelProfile createFromInputStream (InputStream inputStream )
8081 throws IllegalArgumentException {
81- return new BazelProfile (
82+ return BazelProfile . create (
8283 new JsonReader (new InputStreamReader (inputStream , StandardCharsets .UTF_8 )));
8384 }
8485
8586 private final BazelVersion bazelVersion ;
86- private final Map <String , String > otherData = new HashMap <>();
87- private final Map <ThreadId , ProfileThread > threads = new HashMap <>();
87+ private final ImmutableMap <String , String > otherData ;
88+ private final ImmutableMap <ThreadId , ProfileThread > threads ;
89+ private final ProfileThread mainThread ;
90+ private final Optional <ProfileThread > criticalPath ;
91+ private final Optional <ProfileThread > gcThread ;
92+
93+ private BazelProfile (
94+ BazelVersion bazelVersion ,
95+ ImmutableMap <String , String > otherData ,
96+ ImmutableMap <ThreadId , ProfileThread > threads ,
97+ ProfileThread mainThread ,
98+ Optional <ProfileThread > criticalPath ,
99+ Optional <ProfileThread > gcThread ) {
100+ this .bazelVersion = Preconditions .checkNotNull (bazelVersion );
101+ this .otherData = Preconditions .checkNotNull (otherData );
102+ this .threads = Preconditions .checkNotNull (threads );
103+ this .mainThread = Preconditions .checkNotNull (mainThread );
104+ this .criticalPath = Preconditions .checkNotNull (criticalPath );
105+ this .gcThread = Preconditions .checkNotNull (gcThread );
106+ }
88107
89- private BazelProfile (JsonReader profileReader ) {
108+ private static BazelProfile create (JsonReader profileReader ) {
109+ Map <String , String > otherData = new HashMap <>();
110+ Map <ThreadId , ProfileThread > threads = new HashMap <>();
90111 try {
91112 boolean hasOtherData = false ;
92113 boolean hasTraceEvents = false ;
@@ -116,15 +137,11 @@ private BazelProfile(JsonReader profileReader) {
116137 continue ;
117138 }
118139 ThreadId threadId = new ThreadId (pid , tid );
119- ProfileThread profileThread =
120- threads .compute (
121- threadId ,
122- (key , t ) -> {
123- if (t == null ) {
124- t = new ProfileThread (threadId );
125- }
126- return t ;
127- });
140+ ProfileThread profileThread = threads .get (threadId );
141+ if (profileThread == null ) {
142+ profileThread = new ProfileThread (threadId );
143+ threads .put (threadId , profileThread );
144+ }
128145 // TODO: Use success response to take action on errant events.
129146 profileThread .addEvent (traceEvent );
130147 }
@@ -147,23 +164,34 @@ private BazelProfile(JsonReader profileReader) {
147164 throw new IllegalArgumentException ("Could not parse Bazel profile." , e );
148165 }
149166
150- this . bazelVersion =
167+ BazelVersion bazelVersion =
151168 BazelVersion .parse (otherData .get (BazelProfileConstants .OTHER_DATA_BAZEL_VERSION ));
169+ ProfileThread mainThread = null ;
170+ ProfileThread criticalPath = null ;
171+ ProfileThread gcThread = null ;
172+ for (ProfileThread e : threads .values ()) {
173+ if (mainThread == null && isMainThread (e )) {
174+ mainThread = e ;
175+ } else if (criticalPath == null && isCriticalPathThread (e )) {
176+ criticalPath = e ;
177+ } else if (gcThread == null && isGarbageCollectorThread (e )) {
178+ gcThread = e ;
179+ }
180+ }
152181
153- if (! containsMainThread () ) {
182+ if (mainThread == null ) {
154183 throw new IllegalArgumentException (
155184 String .format (
156185 "Invalid Bazel profile, JSON file missing \" %s\" ." ,
157186 BazelProfileConstants .THREAD_MAIN ));
158187 }
159- }
160-
161- /**
162- * This method is called from the constructor. Either it needs to stay private or it must be
163- * declared final, so that it cannot be overridden.
164- */
165- private boolean containsMainThread () {
166- return threads .values ().stream ().anyMatch (BazelProfile ::isMainThread );
188+ return new BazelProfile (
189+ bazelVersion ,
190+ ImmutableMap .copyOf (otherData ),
191+ ImmutableMap .copyOf (threads ),
192+ mainThread ,
193+ Optional .ofNullable (criticalPath ),
194+ Optional .ofNullable (gcThread ));
167195 }
168196
169197 /**
@@ -228,15 +256,15 @@ public Stream<ProfileThread> getThreads() {
228256 }
229257
230258 public Optional <ProfileThread > getCriticalPath () {
231- return threads . values (). stream (). filter ( BazelProfile :: isCriticalPathThread ). findAny () ;
259+ return criticalPath ;
232260 }
233261
234262 public ProfileThread getMainThread () {
235- return threads . values (). stream (). filter ( BazelProfile :: isMainThread ). findAny (). get () ;
263+ return mainThread ;
236264 }
237265
238266 public Optional <ProfileThread > getGarbageCollectorThread () {
239- return threads . values (). stream (). filter ( BazelProfile :: isGarbageCollectorThread ). findAny () ;
267+ return gcThread ;
240268 }
241269
242270 public Optional <ImmutableList <CounterEvent >> getActionCounts () {
0 commit comments