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

[Internship] Benchmarking remote execution #346

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
12 changes: 12 additions & 0 deletions example.iml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
Copy link
Collaborator

Choose a reason for hiding this comment

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

What is this file? Do things work without it? We should not need config files like this

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This seems to be a file created by IntelliJ to keep the module configuration. The program should work without it.

<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
13 changes: 13 additions & 0 deletions java/com/engflow/internship/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Example Projects for Performance Testing

## Overview

Welcome to the `internship` folder of the EngFlow examples repository. This folder contains a set of example projects designed to evaluate and benchmark the performance of EngFlow's remote execution and caching services. These projects aim to provide a diverse range of test cases with varying input sizes, numbers of inputs, and execution times. The goal is to generate performance data that can help in understanding how different factors affect the performance of remote build optimization services.

## Purpose

The primary objectives of these example projects are to:

1. **Generate Performance Data**: Create examples with varying complexity to test and gather performance data for EngFlow’s remote caching and execution services.
2. **Benchmark Analysis**: Compare the performance of local versus remote execution and caching to evaluate the efficiency and effectiveness of the service.
3. **Support Automation Development**: Contribute to the development of automation algorithms for resource assignment by providing valuable data on how the size and nature of the builds impact performance.
32 changes: 32 additions & 0 deletions java/com/engflow/internship/binaryinput/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
load("@rules_java//java:defs.bzl", "java_binary", "java_library")

NUM_FILES = 10

#Main class
java_binary(
name = "main",
srcs = ["Main.java"],
main_class = "com.engflow.internship.binaryinput.Main",
deps = [
":genbinary"
],
args = [str(NUM_FILES)],
)

#Generates a number of java files based on the value of NUM_FILES
#Each file is named HelloX.java where X is the number of the file
#Each file contains a class with a greetNum method that prints "Hello" + the number of the file
[genrule(
name = "Hello" + str(x),
outs = ["Hello" + str(x) + ".java"],
cmd_bash = "echo 'package com.engflow.internship.binaryinput;" + "\n" +
"public class Hello" + str(x) +
" { public static void greetNum() { System.out.println(\"Hello " + str(x) + "\"); } }' > $@",
) for x in range(1,NUM_FILES+1)]

#Generates a java library that contains all the generated java files
java_library(
name = "genbinary",
srcs = [":Hello" + str(x) + ".java" for x in range(1,NUM_FILES+1)],
visibility = ["//visibility:public"],
)
21 changes: 21 additions & 0 deletions java/com/engflow/internship/binaryinput/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.engflow.internship.binaryinput;

import java.lang.reflect.InvocationTargetException;

public class Main {
public static void main(String[] args) {
try {
// args[0] is the number of files to read
int numFiles = Integer.parseInt(args[0]);

// Load and run the greetNum method from each class
for(int i = 1; i <= numFiles; i++){
Class<?> clazz = Class.forName("com.engflow.internship.binaryinput.Hello" + i);
clazz.getMethod("greetNum").invoke(null);
}

} catch (ClassNotFoundException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
52 changes: 52 additions & 0 deletions java/com/engflow/internship/binaryinput/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Multiple Binary Input Example

## Overview

The goal of this example project is to test the performance of Engflow's remote execution and caching service based on the number of input binary files in the dependency graph. The project contains a `genrule` that generates a specified number of Java binaries for the `genbinary` Java library, which are then listed as dependencies in the main binary. The `Main.java` file loops through each generated class and calls its `greetNum` method.

## Project Structure

- `java/com/engflow/internship/binaryinput/Main.java`: Main class that dynamically loads and invokes methods from generated classes.
- `java/com/engflow/internship/binaryinput/BUILD`: Bazel build file for the `main` java binary and the `genbinary` library.

## Usage

To generate the test files, build the `genbinary` library using the `genrule`:
```sh
bazel build //java/com/engflow/internship/binaryinput:genbinary
```

Then, the program can be run with the following command:
```sh
bazel run //java/com/engflow/internship/binaryinput:main
```

## How It Works

1. **Generation of Java Binaries:**
- The `genrule` in the `BUILD` file generates a specified number of Java classes (`Hello1.java`, `Hello2.java`, ..., `HelloN.java`).
- Each generated class contains a `greetNum` method that prints a unique message.

2. **Main Class Execution:**
- The `Main.java` file in `binaryinput` dynamically loads each generated class using reflection.
- It then invokes the `greetNum` method of each class, printing the corresponding message.

## Configuration

The number of generated files is controlled by the `NUM_FILES` variable in the `BUILD` file of the `binaryinput` package. Modify this variable to change the number of generated classes and observe the performance impact on Engflow's remote execution and caching service.

## Example

To generate and run the program with 10 input binary files:

1. Set `NUM_FILES` to 10 in `java/com/engflow/internship/binaryinput/BUILD`.
2. Build the `genbinary` library:
```sh
bazel build //java/com/engflow/internship/binaryinput:genbinary
```
3. Run the `main` binary:
```sh
bazel run //java/com/engflow/internship/binaryinput:main
```

This will generate 10 Java classes, build the `genbinary` library, and run the `main` binary, which will print messages from each generated class.
36 changes: 36 additions & 0 deletions java/com/engflow/internship/cycleexample/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Cyclical Dependency Example

## Overview

This project is designed to evaluate and benchmark the performance of EngFlow's remote execution and caching services. It specifically focuses on testing scenarios involving cyclical-like structures in the dependency graph, which are handled through interfaces and constructor injection.

## Purpose

The primary objectives of this project are to:

1. **Generate Performance Data**: Create examples with cyclical-like dependencies to test and gather performance data for EngFlow’s remote caching and execution services.
2. **Benchmark Analysis**: Compare the performance of local versus remote execution and caching to evaluate the efficiency and effectiveness of the service.
3. **Support Automation Development**: Contribute to the development of automation algorithms for resource assignment by providing valuable data on how cyclical dependencies impact performance.

## Project Structure

The project is organized into several packages, each representing different components of the cyclical dependency example:

- `class_a`: Contains `ClassA` which depends on `ClassB` through an interface.
- `class_b`: Contains `ClassB` which implements `InterfaceB` and depends on `ClassC`.
- `class_c`: Contains `ClassC` which implements `InterfaceA` and can be initialized with a reference to `ClassA`.
- `interface_a`: Defines the interface `InterfaceA` implemented by `ClassA` and `ClassC`.
- `interface_b`: Defines the interface `InterfaceB` implemented by `ClassB`.
- `main`: Contains the `Main` class which processes the input file.
- `input`: Contains the input text file used by the `Main` class.

## How the Program Works

The program takes a text input file and recursively prints each word with each class (`ClassA` prints a word, then `ClassB`, and so on) until the string is empty. The input file should be specified in the `data` attribute of the `java_binary` rule in the `BUILD` file.

## How to Run Tests

To run the tests and gather performance data, use the following Bazel command:

```sh
bazel test //java/com/engflow/internship/cycleexample/class_a:class_a_test
22 changes: 22 additions & 0 deletions java/com/engflow/internship/cycleexample/class_a/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package(default_visibility = ["//visibility:public"])

java_library(
name = "class_a",
srcs = ["ClassA.java"],
deps = [
"//java/com/engflow/internship/cycleexample/class_b",
"//java/com/engflow/internship/cycleexample/interface_a",
],
)

java_test(
name = "class_a_test",
srcs = ["ClassATest.java"],
test_class = "com.engflow.internship.cycleexample.class_a.ClassATest",
deps = [
":class_a",
"//java/com/engflow/internship/cycleexample/class_b:class_b",
"//java/com/engflow/internship/cycleexample/class_c:class_c",
"//java/com/engflow/internship/cycleexample/interface_a:interface_a",
],
)
31 changes: 31 additions & 0 deletions java/com/engflow/internship/cycleexample/class_a/ClassA.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.engflow.internship.cycleexample.class_a;

import com.engflow.internship.cycleexample.class_b.ClassB;
import com.engflow.internship.cycleexample.interface_a.InterfaceA;

public class ClassA implements InterfaceA {
private ClassB classB;

public ClassA(ClassB classB) {
this.classB = classB;
}

@Override
public void methodA(String input) {
// If the input is null or empty, return immediately
if (input == null || input.isEmpty()) {
return;
}

//Find the index of the first space character in the input string.
int spaceIndex = input.indexOf(' ');
//Extract the word from the beginning of the input string up to the space character.
String word = (spaceIndex == -1) ? input : input.substring(0, spaceIndex);
//Extract the remaining part of the input string after the space character.
String remaining = (spaceIndex == -1) ? "" : input.substring(spaceIndex + 1);

//Print the word extracted from the input string.
System.out.println("ClassA: " + word);
classB.methodB(remaining);
}
}
42 changes: 42 additions & 0 deletions java/com/engflow/internship/cycleexample/class_a/ClassATest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.engflow.internship.cycleexample.class_a;

import com.engflow.internship.cycleexample.class_b.ClassB;
import com.engflow.internship.cycleexample.class_c.ClassC;
import org.junit.Test;
import static org.junit.Assert.assertTrue;

public class ClassATest {
private static class TestClassB extends ClassB {
boolean methodBCalled = false;

public TestClassB(ClassC classC) {
super(classC);
}

@Override
public void methodB(String input) {
methodBCalled = true;
}
}

@Test
public void testMethodA() {
// Create a ClassC instance with a null ClassA object
ClassC classC = new ClassC(null);

// Create a TestClassB instance with the ClassC object
TestClassB testClassB = new TestClassB(classC);

// Create a new ClassA instance with the TestClassB object
ClassA classA = new ClassA(testClassB);

// Properly initialize classC with classA
classC.setClassA(classA);

// Call methodA on classA with a sample input
classA.methodA("sample input");

// Verify that methodB on the TestClassB was called
assertTrue(testClassB.methodBCalled);
}
}
21 changes: 21 additions & 0 deletions java/com/engflow/internship/cycleexample/class_b/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package(default_visibility = ["//visibility:public"])

java_library(
name = "class_b",
srcs = ["ClassB.java"],
deps = [
"//java/com/engflow/internship/cycleexample/class_c",
"//java/com/engflow/internship/cycleexample/interface_b",
],
)

java_test(
name = "class_b_test",
srcs = ["ClassBTest.java"],
test_class = "com.engflow.internship.cycleexample.class_b.ClassBTest",
deps = [
":class_b",
"//java/com/engflow/internship/cycleexample/class_c:class_c",
"//java/com/engflow/internship/cycleexample/interface_b:interface_b",
],
)
31 changes: 31 additions & 0 deletions java/com/engflow/internship/cycleexample/class_b/ClassB.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.engflow.internship.cycleexample.class_b;

import com.engflow.internship.cycleexample.class_c.ClassC;
import com.engflow.internship.cycleexample.interface_b.InterfaceB;

public class ClassB implements InterfaceB {
private ClassC classC;

public ClassB(ClassC classC) {
this.classC = classC;
}

@Override
public void methodB(String input) {
// If the input is null or empty, return immediately
if (input == null || input.isEmpty()) {
return;
}

//Find the index of the first space character in the input string.
int spaceIndex = input.indexOf(' ');
//Extract the word from the beginning of the input string up to the space character.
String word = (spaceIndex == -1) ? input : input.substring(0, spaceIndex);
//Extract the remaining part of the input string after the space character.
String remaining = (spaceIndex == -1) ? "" : input.substring(spaceIndex + 1);

//Print the word extracted from the input string.
System.out.println("ClassB: " + word);
classC.methodA(remaining);
}
}
35 changes: 35 additions & 0 deletions java/com/engflow/internship/cycleexample/class_b/ClassBTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.engflow.internship.cycleexample.class_b;

import com.engflow.internship.cycleexample.class_c.ClassC;
import org.junit.Test;
import static org.junit.Assert.assertTrue;

public class ClassBTest {
private static class TestClassC extends ClassC {
boolean methodACalled = false;

public TestClassC() {
super(null);
}

@Override
public void methodA(String input) {
methodACalled = true;
}
}

@Test
public void testMethodB() {
// Create a TestClassC instance
TestClassC testClassC = new TestClassC();

// Create an instance of ClassB with the TestClassC object
ClassB classB = new ClassB(testClassC);

// Call methodB on classB
classB.methodB("Sample input");

// Verify that methodA on the TestClassC was called
assertTrue(testClassC.methodACalled);
}
}
20 changes: 20 additions & 0 deletions java/com/engflow/internship/cycleexample/class_c/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package(default_visibility = ["//visibility:public"])

java_library(
name = "class_c",
srcs = ["ClassC.java"],
visibility = ["//visibility:public"],
deps = [
"//java/com/engflow/internship/cycleexample/interface_a",
],
)

java_test(
name = "class_c_test",
srcs = ["ClassCTest.java"],
test_class = "com.engflow.internship.cycleexample.class_c.ClassCTest",
deps = [
":class_c",
"//java/com/engflow/internship/cycleexample/class_a:class_a",
],
)
Loading
Loading