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 ;
4243import java .util .Map ;
4344import java .util .Optional ;
4445import java .util .concurrent .atomic .AtomicLong ;
45- import java .util .stream .Collectors ;
4646import java .util .stream .Stream ;
4747import java .util .zip .GZIPInputStream ;
4848import java .util .zip .ZipException ;
@@ -80,21 +80,40 @@ public static BazelProfile createFromPath(String path) throws IllegalArgumentExc
8080
8181 public static BazelProfile createFromInputStream (InputStream inputStream )
8282 throws IllegalArgumentException {
83- return new BazelProfile (
83+ return BazelProfile . create (
8484 new JsonReader (new InputStreamReader (inputStream , StandardCharsets .UTF_8 )));
8585 }
8686
8787 public static BazelProfile of (Reader reader ) {
88- return new BazelProfile (new JsonReader (reader ));
88+ return BazelProfile . create (new JsonReader (reader ));
8989 }
9090
9191 private final BazelVersion bazelVersion ;
92- private final Map <String , String > otherData = new HashMap <>();
93- private final Map <ThreadId , ProfileThread > threads ;
92+ private final ImmutableMap <String , String > otherData ;
93+ private final ImmutableMap <ThreadId , ProfileThread > threads ;
94+ private final ProfileThread mainThread ;
95+ private final Optional <ProfileThread > criticalPath ;
96+ private final Optional <ProfileThread > gcThread ;
97+
98+ private BazelProfile (
99+ BazelVersion bazelVersion ,
100+ ImmutableMap <String , String > otherData ,
101+ ImmutableMap <ThreadId , ProfileThread > threads ,
102+ ProfileThread mainThread ,
103+ Optional <ProfileThread > criticalPath ,
104+ Optional <ProfileThread > gcThread ) {
105+ this .bazelVersion = Preconditions .checkNotNull (bazelVersion );
106+ this .otherData = Preconditions .checkNotNull (otherData );
107+ this .threads = Preconditions .checkNotNull (threads );
108+ this .mainThread = Preconditions .checkNotNull (mainThread );
109+ this .criticalPath = Preconditions .checkNotNull (criticalPath );
110+ this .gcThread = Preconditions .checkNotNull (gcThread );
111+ }
94112
95- private BazelProfile (JsonReader profileReader ) {
113+ private static BazelProfile create (JsonReader profileReader ) {
114+ ImmutableMap .Builder <String , String > otherDataBuilder = ImmutableMap .builder ();
115+ Map <ThreadId , ProfileThread .Builder > threadBuilders = new HashMap <>();
96116 try {
97- Map <ThreadId , ProfileThread .Builder > threadBuilders = new HashMap <>();
98117 boolean hasOtherData = false ;
99118 boolean hasTraceEvents = false ;
100119 profileReader .beginObject ();
@@ -104,7 +123,7 @@ private BazelProfile(JsonReader profileReader) {
104123 hasOtherData = true ;
105124 profileReader .beginObject ();
106125 while (profileReader .hasNext ()) {
107- otherData .put (profileReader .nextName (), profileReader .nextString ());
126+ otherDataBuilder .put (profileReader .nextName (), profileReader .nextString ());
108127 }
109128 profileReader .endObject ();
110129 break ;
@@ -123,15 +142,11 @@ private BazelProfile(JsonReader profileReader) {
123142 continue ;
124143 }
125144 ThreadId threadId = new ThreadId (pid , tid );
126- ProfileThread .Builder profileThreadBuilder =
127- threadBuilders .compute (
128- threadId ,
129- (key , t ) -> {
130- if (t == null ) {
131- t = new ProfileThread .Builder ().setThreadId (key );
132- }
133- return t ;
134- });
145+ ProfileThread .Builder profileThreadBuilder = threadBuilders .get (threadId );
146+ if (profileThreadBuilder == null ) {
147+ profileThreadBuilder = new ProfileThread .Builder ().setThreadId (threadId );
148+ threadBuilders .put (threadId , profileThreadBuilder );
149+ }
135150 // TODO: Use success response to take action on errant events.
136151 profileThreadBuilder .addEvent (traceEvent );
137152 }
@@ -150,30 +165,41 @@ private BazelProfile(JsonReader profileReader) {
150165 TraceEventFormatConstants .SECTION_OTHER_DATA ,
151166 TraceEventFormatConstants .SECTION_TRACE_EVENTS ));
152167 }
153- threads =
154- threadBuilders .entrySet ().stream ()
155- .collect (Collectors .toMap (Map .Entry ::getKey , e -> e .getValue ().build ()));
156168 } catch (IllegalStateException | IOException e ) {
157169 throw new IllegalArgumentException ("Could not parse Bazel profile." , e );
158170 }
159171
160- this .bazelVersion =
172+ ImmutableMap <String , String > otherData = otherDataBuilder .build ();
173+ BazelVersion bazelVersion =
161174 BazelVersion .parse (otherData .get (BazelProfileConstants .OTHER_DATA_BAZEL_VERSION ));
162-
163- if (!containsMainThread ()) {
175+ ImmutableMap .Builder <ThreadId , ProfileThread > threadsMapBuilder = ImmutableMap .builder ();
176+ ProfileThread mainThread = null ;
177+ ProfileThread criticalPath = null ;
178+ ProfileThread gcThread = null ;
179+ for (Map .Entry <ThreadId , ProfileThread .Builder > entry : threadBuilders .entrySet ()) {
180+ ProfileThread t = entry .getValue ().build ();
181+ if (mainThread == null && isMainThread (t )) {
182+ mainThread = t ;
183+ } else if (criticalPath == null && isCriticalPathThread (t )) {
184+ criticalPath = t ;
185+ } else if (gcThread == null && isGarbageCollectorThread (t )) {
186+ gcThread = t ;
187+ }
188+ threadsMapBuilder .put (entry .getKey (), t );
189+ }
190+ if (mainThread == null ) {
164191 throw new IllegalArgumentException (
165192 String .format (
166193 "Invalid Bazel profile, JSON file missing \" %s\" ." ,
167194 BazelProfileConstants .THREAD_MAIN ));
168195 }
169- }
170-
171- /**
172- * This method is called from the constructor. Either it needs to stay private or it must be
173- * declared final, so that it cannot be overridden.
174- */
175- private boolean containsMainThread () {
176- return threads .values ().stream ().anyMatch (BazelProfile ::isMainThread );
196+ return new BazelProfile (
197+ bazelVersion ,
198+ otherData ,
199+ threadsMapBuilder .build (),
200+ mainThread ,
201+ Optional .ofNullable (criticalPath ),
202+ Optional .ofNullable (gcThread ));
177203 }
178204
179205 /**
@@ -238,15 +264,15 @@ public Stream<ProfileThread> getThreads() {
238264 }
239265
240266 public Optional <ProfileThread > getCriticalPath () {
241- return threads . values (). stream (). filter ( BazelProfile :: isCriticalPathThread ). findAny () ;
267+ return criticalPath ;
242268 }
243269
244270 public ProfileThread getMainThread () {
245- return threads . values (). stream (). filter ( BazelProfile :: isMainThread ). findAny (). get () ;
271+ return mainThread ;
246272 }
247273
248274 public Optional <ProfileThread > getGarbageCollectorThread () {
249- return threads . values (). stream (). filter ( BazelProfile :: isGarbageCollectorThread ). findAny () ;
275+ return gcThread ;
250276 }
251277
252278 public Optional <ImmutableList <CounterEvent >> getActionCounts () {
0 commit comments