Skip to content
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
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ java -jar target/cloudsimplus-benchmarks-8.5.1-uber.jar -l
Alternative entry points (run from the IDE or with `exec`/`java -cp`):
- `org.cloudsimplus.benchmarks.Run` runs every JMH benchmark matching `org.cloudsimplus.` with preset options (1 fork, 5 warmup, 25 measurement iterations, ms, 1 thread).
- `org.cloudsimplus.benchmarks.SimulationTimeBenchmark` is a plain `main` (not JMH): it runs a full simulation several times, growing Hosts/VMs/Cloudlets each run, and prints execution time.
- `org.cloudsimplus.listeners.ListenersMemoryBenchmark` is a plain `main` (not JMH): it prints the heap retained by each VM and Host (run it with `-XX:+UseSerialGC`). To compare with CloudSim Plus 8.5.1 (before issue #586), build with `./mvnw clean package -Pcloudsimplus-8`, run it, then build without the profile and run it again (see its Javadoc).
- `org.cloudsimplus.benchmarks.MemoryFootprintBenchmark` is a plain `main` (not JMH): it prints the heap retained by each VM, Host and Cloudlet, i.e., their memory footprint (run it with `-XX:+UseSerialGC`). To compare with CloudSim Plus 8.5.1 (before issues #586 and #587), build with `./mvnw clean package -Pcloudsimplus-8`, run it, then build without the profile and run it again (see its Javadoc).

There are no unit tests in this project.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
* You should have received a copy of the GNU General Public License
* along with CloudSim Plus. If not, see <http://www.gnu.org/licenses/>.
*/
package org.cloudsimplus.listeners;
package org.cloudsimplus.benchmarks;

import org.cloudsimplus.cloudlets.CloudletSimple;
import org.cloudsimplus.hosts.HostSimple;
import org.cloudsimplus.resources.PeSimple;
import org.cloudsimplus.vms.VmSimple;
Expand All @@ -34,10 +35,16 @@
import java.util.List;
import java.util.function.IntFunction;

/// Measures the heap retained by each VM and Host, to compare the memory used
/// before and after the listener lists became the shared `List.of()` (issue #586).
/// Before that, each VM created 6 empty `ArrayList`s and each Host created
/// 2 empty `ArrayList`s and 1 empty `HashSet`, even when no listener was added.
/// Measures the heap retained by each VM, Host and Cloudlet (their memory footprint),
/// to compare CloudSim Plus versions. Since it measures the whole object (with everything it references),
/// it includes all changes that affect the footprint, such as:
/// - [#586](https://github.com/cloudsimplus/cloudsimplus/issues/586): listener lists start as the shared `List.of()`.
/// Before that, each VM created 6 empty `ArrayList`s and each Host created
/// 2 empty `ArrayList`s and 1 empty `HashSet`, even when no listener was added.
/// - [#587](https://github.com/cloudsimplus/cloudsimplus/issues/587): reduces the Cloudlet footprint.
/// Before that, each Cloudlet created 3 empty listener `HashSet`s, an empty `requiredFiles` `LinkedList`
/// and a new `UtilizationModelFull` for its CPU. Now, the listener and `requiredFiles` lists start as the shared `List.of()`,
/// and the CPU uses the shared `UtilizationModel.FULL`.
///
/// It's a plain `main` (not JMH), since JMH measures time and allocation rate,
/// but here we need the memory that stays in the heap after the objects are created.
Expand All @@ -48,20 +55,19 @@
/// The results are only accurate with a stop-the-world GC, where [System#gc()]
/// does a full collection, so run it with `-XX:+UseSerialGC`.
///
/// To compare CloudSim Plus 8.5.1 (before #586) with the current version, build and run it once for each version:
/// To compare CloudSim Plus 8.5.1 (before #586 and #587) with the current version, build and run it once for each version:
///
/// ```bash
/// ./mvnw clean package -Pcloudsimplus-8 # CloudSim Plus 8.5.1
/// java -XX:+UseSerialGC -cp target/cloudsimplus-benchmarks-*-uber.jar org.cloudsimplus.listeners.ListenersMemoryBenchmark 8.5.1
/// java -XX:+UseSerialGC -cp target/cloudsimplus-benchmarks-*-uber.jar org.cloudsimplus.benchmarks.MemoryFootprintBenchmark 8.5.1
///
/// ./mvnw clean package # current CloudSim Plus version
/// java -XX:+UseSerialGC -cp target/cloudsimplus-benchmarks-*-uber.jar org.cloudsimplus.listeners.ListenersMemoryBenchmark current
/// java -XX:+UseSerialGC -cp target/cloudsimplus-benchmarks-*-uber.jar org.cloudsimplus.benchmarks.MemoryFootprintBenchmark current
/// ```
///
/// @author Manoel Campos da Silva Filho
/// @see <a href="https://github.com/cloudsimplus/cloudsimplus/issues/586">CloudSim Plus issue #586</a>
/// @see <a href="https://github.com/cloudsimplus/cloudsimplus/issues/523">CloudSim Plus issue #523</a>
public final class ListenersMemoryBenchmark {
public final class MemoryFootprintBenchmark {
/// Number of objects of each type created in each round.
private static final int OBJECTS = 100_000;

Expand All @@ -80,20 +86,24 @@ public final class ListenersMemoryBenchmark {
private static final long HOST_BW = 10_000;
private static final long HOST_STORAGE = 100_000;

private static final long CLOUDLET_LENGTH = 10_000;
private static final int CLOUDLET_PES = 1;

private static final MemoryMXBean MEMORY = ManagementFactory.getMemoryMXBean();

/// A private constructor to avoid class instantiation.
private ListenersMemoryBenchmark(){}
private MemoryFootprintBenchmark(){}

/// Runs the benchmark.
/// @param args an optional label to identify the CloudSim Plus version being measured (e.g., "before" or "after")
public static void main(final String[] args) {
final String label = args.length > 0 ? args[0] : "current";
System.out.printf("%s (%s): %,d objects per round, median of %d rounds%n",
ListenersMemoryBenchmark.class.getSimpleName(), label, OBJECTS, ROUNDS);
MemoryFootprintBenchmark.class.getSimpleName(), label, OBJECTS, ROUNDS);

printResult("VmSimple", measure(ListenersMemoryBenchmark::newVm));
printResult("HostSimple", measure(ListenersMemoryBenchmark::newHost));
printResult("VmSimple", measure(MemoryFootprintBenchmark::newVm));
printResult("HostSimple", measure(MemoryFootprintBenchmark::newHost));
printResult("CloudletSimple", measure(MemoryFootprintBenchmark::newCloudlet));
}

private static VmSimple newVm(final int index) {
Expand All @@ -106,6 +116,11 @@ private static HostSimple newHost(final int index) {
return new HostSimple(HOST_RAM, HOST_BW, HOST_STORAGE, List.of(new PeSimple(PE_MIPS)));
}

/// Creates a Cloudlet with the default utilization models.
private static CloudletSimple newCloudlet(final int index) {
return new CloudletSimple(CLOUDLET_LENGTH, CLOUDLET_PES);
}

/// {@return the median heap (in bytes) retained by each object created by a given function}
/// @param factory a function that creates an object for a given index
private static double measure(final IntFunction<Object> factory) {
Expand Down Expand Up @@ -148,6 +163,6 @@ private static double median(final double[] values) {
}

private static void printResult(final String className, final double bytesPerObject) {
System.out.printf(" %-10s %8.1f bytes per object%n", className, bytesPerObject);
System.out.printf(" %-14s %8.1f bytes per object%n", className, bytesPerObject);
}
}
Loading