Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test perf, eliminate deploy jars from test classpath #391

Merged
merged 1 commit into from
Jan 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

import com.salesforce.bazel.sdk.command.BazelWorkspaceCommandRunner;
import com.salesforce.bazel.sdk.logging.LogHelper;
Expand Down Expand Up @@ -132,8 +131,19 @@ private Long generateCacheKey(boolean isSource, String testClassName, BazelProje
return key;
}

/**
* Convenience bundle of the test param files generated from a set of targets
*/
public static class ParamFileResult {
public Set<File> paramFiles = new HashSet<>();
/**
* The ordered list of param files obtained by querying on the targets
*/
public List<File> paramFiles = new ArrayList<>();

/**
* Labels that did not resolve to a param file. Usually means the test class is not referenced by
* a java_test target, but is a different kind of test that we don't know how to run.
*/
public Set<String> unrunnableLabels = new HashSet<>();
}

Expand Down Expand Up @@ -282,11 +292,22 @@ public Set<File> findParamsFileForTestClassnameAndTarget(BazelWorkspace bazelWor
* Given the set of param files in the passed testParamFilesResult, parse each param file and extract a list
* of jar files from the sources and output sections of each file. Then assemble a de-duplicated list of these
* jar files. The path for each jar file comes from the param file and is known to be relative to the Bazel
* exec root of the workspace.
* exec root of the workspace.
* <p>
* @param testParamFiles the ordered list of discovered param files for the set of targets
* @param includeDeployJars deploy jars contain the Bazel test runner and the full classpath of classes to run
* the test. For some environments, this isn't necessary because the environment externally specifies
* the classpath at launch, and provides the test runner (e.g. Eclipse RemoteTestRunner)
* @return a List of paths to jar files; the list is ordered the same as the param files
*/
public Set<String> aggregateJarFilesFromParamFiles(BazelJvmTestClasspathHelper.ParamFileResult testParamFilesResult) {
Set<String> allPaths = new TreeSet<>();
for (File paramsFile : testParamFilesResult.paramFiles) {
public List<String> aggregateJarFilesFromParamFiles(List<File> testParamFiles,
boolean includeDeployJars) {

// Bazel is deterministic in the ordering of classpath elements, so use a list here not a Set
// to allow us to better model the classpath order of Bazel
List<String> allPaths = new ArrayList<>();

for (File paramsFile : testParamFiles) {
List<String> jarPaths = null;
try {
jarPaths = getClasspathJarsFromParamsFile(paramsFile);
Expand All @@ -299,6 +320,15 @@ public Set<String> aggregateJarFilesFromParamFiles(BazelJvmTestClasspathHelper.P
}

for (String jarPath : jarPaths) {
if (!includeDeployJars && jarPath.endsWith("_deploy.jar")) {
Copy link
Contributor Author

@plaird plaird Jan 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if statement is the key to this PR.

// deploy jars are bloated and redundant for some callers, exclude them if asked to
continue;
}
if (allPaths.contains(jarPath)) {
// we don't want dupes
continue;
}

// it is important to use a Set for allPaths, as the jarPaths will contain many dupes
// across ParamFiles and we only want each one listed once
allPaths.add(jarPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ public class BasicLoggerFacade extends LoggerFacade {
@Override
protected void error(Class<?> from, String message, Object... args) {
// LoggerFactory.getLogger(from).error(message, args);
if (args != null && args.length > 0) {
Object firstArg = args[0];
if (firstArg instanceof Throwable) {
Throwable anyE = (Throwable)firstArg;
anyE.printStackTrace();
}
}
System.err.println("ERROR " + formatMsg(from, message, args));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ public class BazelClasspathContainerInitializer extends ClasspathContainerInitia
@Override
public void initialize(IPath eclipseProjectPath, IJavaProject eclipseJavaProject) throws CoreException {
IProject eclipseProject = eclipseJavaProject.getProject();
String eclipseProjectName = eclipseProject.getName();
try {
//remove projects added to the workspace after a corrupted package in identified
if (isCorrupt.get()) {
Expand All @@ -81,7 +82,7 @@ public void initialize(IPath eclipseProjectPath, IJavaProject eclipseJavaProject

// create the BazelProject if necessary
BazelProjectManager bazelProjectManager = ComponentContext.getInstance().getProjectManager();
BazelProject bazelProject = bazelProjectManager.getProject(eclipseProject.getName());
BazelProject bazelProject = bazelProjectManager.getProject(eclipseProjectName);
if (bazelProject == null) {
bazelProject = new BazelProject(eclipseProject.getName(), eclipseProject);
bazelProjectManager.addProject(bazelProject);
Expand All @@ -95,10 +96,10 @@ public void initialize(IPath eclipseProjectPath, IJavaProject eclipseJavaProject
} else {
setClasspathContainerForProject(eclipseProjectPath, eclipseJavaProject, container);
}
} catch (IOException | InterruptedException | BackingStoreException e) {
LOG.error("Error while creating Bazel classpath container.", e);
} catch (BazelCommandLineToolConfigurationException e) {
LOG.error("Bazel not found: " + e.getMessage());
} catch (Exception anyE) {
LOG.error("Error while initializing Bazel classpath container for project {}", anyE, eclipseProjectName);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,12 @@ IRuntimeClasspathEntry[] computeUnresolvedClasspathFromParamFiles(File execRootD
BazelJvmTestClasspathHelper.ParamFileResult testParamFilesResult) throws CoreException {
List<IRuntimeClasspathEntry> result = new ArrayList<>();

// assemble the de-duplicated list of jar files that are used across all the test targets
// these paths are listed in the param files, and are relative to the Bazel workspace exec root
Set<String> jarPaths = bazelJvmTestClasspathHelper.aggregateJarFilesFromParamFiles(testParamFilesResult);
// Assemble the de-duplicated list of jar files that are used across all the test targets
// these paths are listed in the param files, and are relative to the Bazel workspace exec root.
// We don't want deploy jars, because those are bloated and kill performance. Eclipse passes the project classpath
// to the RemoteTestRunner JVM so we don't need the self-contained deploy jars.
boolean includeDeployJars = false;
List<String> jarPaths = bazelJvmTestClasspathHelper.aggregateJarFilesFromParamFiles(testParamFilesResult.paramFiles, includeDeployJars);
for (String rawPath : jarPaths) {
String canonicalPath = FSPathHelper.getCanonicalPathStringSafely(new File(execRootDir, rawPath));
IPath eachPath = new Path(canonicalPath);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
import java.util.TreeSet;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import com.salesforce.bazel.sdk.lang.jvm.BazelJvmTestClasspathHelper;
import com.salesforce.bazel.sdk.path.FSPathHelper;

public class BazelJvmTestClasspathHelperTest {
Expand Down Expand Up @@ -82,7 +81,7 @@ public void getParamsJarSuffix() {
@Test
public void testClasspathAggregation() throws Exception {
BazelJvmTestClasspathHelper.ParamFileResult result = new BazelJvmTestClasspathHelper.ParamFileResult();
result.paramFiles = new TreeSet<>();
result.paramFiles = new ArrayList<>();
result.unrunnableLabels = new TreeSet<>();
File tdir = tmpDir.newFolder("paramFiles");
File pdir = new File(tdir, "paramFiles");
Expand All @@ -95,9 +94,14 @@ public void testClasspathAggregation() throws Exception {
result.paramFiles.add(createParamFile(pdir, i));
}

Set<String> jarPaths = bazelJvmTestClasspathHelper.aggregateJarFilesFromParamFiles(result);

boolean includeDeployJars = true;
List<String> jarPaths =
bazelJvmTestClasspathHelper.aggregateJarFilesFromParamFiles(result.paramFiles, includeDeployJars);
assertEquals(7, jarPaths.size());

includeDeployJars = false;
jarPaths = bazelJvmTestClasspathHelper.aggregateJarFilesFromParamFiles(result.paramFiles, includeDeployJars);
assertEquals(5, jarPaths.size());
}

private static File createParamFile(File dir, int index) {
Expand Down