├── VERSION ├── system-load-generator ├── configs ├── const_cpuload_config.yaml ├── cpuload_config.yaml ├── loadaverage_config.yaml └── cpuload_memorypressure_config.yaml ├── .gitignore ├── Dockerfile ├── LICENSE ├── settings.gradle ├── src └── main │ └── java │ └── loadgenerator │ ├── strategies │ ├── LoadGenerationStrategyI.java │ ├── factory │ │ ├── SimpleStrategyFactoryI.java │ │ ├── UnsupportedLoadTypeException.java │ │ └── SimpleStrategyFactory.java │ ├── ConstantCPULoad.java │ ├── ConstIncreaseCPULoad.java │ ├── ConstIncreaseLoadAverage.java │ └── CPULoadGeneratorWithMemoryPressure.java │ ├── driver │ ├── UsageException.java │ ├── CLIBuilder.java │ └── Driver.java │ ├── entities │ └── ProcessorArchInfo.java │ └── util │ ├── ProcessorArch.java │ ├── LoadAverage.java │ └── CPULoad.java └── README.md /VERSION: -------------------------------------------------------------------------------- 1 | 2.1-SNAPSHOT 2 | -------------------------------------------------------------------------------- /system-load-generator: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | gradle run --args="'$@'" -------------------------------------------------------------------------------- /configs/const_cpuload_config.yaml: -------------------------------------------------------------------------------- 1 | cpuLoad: 0.6 2 | duration: 70000 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.swp 3 | .vscode/ 4 | .gradle/ 5 | .idea/ 6 | **/build/ 7 | -------------------------------------------------------------------------------- /configs/cpuload_config.yaml: -------------------------------------------------------------------------------- 1 | stepSize: 0.2 2 | duration: 3000 3 | isAlt: false 4 | segments: 2 5 | -------------------------------------------------------------------------------- /configs/loadaverage_config.yaml: -------------------------------------------------------------------------------- 1 | startLoadAverage: 0.25 # assuming quad-core machine. 2 | stepSize: 0.2 -------------------------------------------------------------------------------- /configs/cpuload_memorypressure_config.yaml: -------------------------------------------------------------------------------- 1 | minCpuLoadPercentage: 0.2 2 | maxCpuLoadPercentage: 0.6 3 | ramUsageBytes: 2048 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Generate CPU load for the given number of threads and cores. 2 | # Generate Load Average. 3 | # Load.java forked from https://gist.github.com/SriramKeerthi/0f1513a62b3b09fecaeb 4 | # Generate CPU Load with Memory Pressure. 5 | 6 | FROM openjdk:8 7 | 8 | # Gradle Installation. 9 | # Cite: https://gordonlesti.com/building-a-gradle-docker-image 10 | # Installing v6.3 as higher versions don't seem to work. 11 | RUN wget -q https://services.gradle.org/distributions/gradle-6.3-bin.zip \ 12 | && unzip gradle-6.3-bin.zip -d /opt \ 13 | && rm gradle-6.3-bin.zip 14 | 15 | ENV GRADLE_HOME /opt/gradle-6.3 16 | ENV PATH $PATH:/opt/gradle-6.3/bin 17 | 18 | # Copying the source files into the Docker container's root directory. 19 | COPY . / 20 | 21 | # Compile. 22 | RUN gradle clean && gradle build 23 | 24 | # Default = help string. 25 | CMD ["-h"] 26 | 27 | ENTRYPOINT ["./system-load-generator"] 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 PRADYUMNA KAUSHIK 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | * 4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | rootProject.name = 'system-load-generator' -------------------------------------------------------------------------------- /src/main/java/loadgenerator/strategies/LoadGenerationStrategyI.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.strategies; 25 | 26 | public interface LoadGenerationStrategyI { 27 | void execute(); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/strategies/factory/SimpleStrategyFactoryI.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.strategies.factory; 25 | 26 | import java.io.IOException; 27 | 28 | import loadgenerator.strategies.LoadGenerationStrategyI; 29 | 30 | public interface SimpleStrategyFactoryI { 31 | LoadGenerationStrategyI getLoadGenerationStrategy(String loadType) 32 | throws UnsupportedLoadTypeException, IOException; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/strategies/factory/UnsupportedLoadTypeException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.strategies.factory; 25 | 26 | public class UnsupportedLoadTypeException extends IllegalArgumentException { 27 | public UnsupportedLoadTypeException(String message) { 28 | super(message); 29 | } 30 | 31 | public UnsupportedLoadTypeException(String message, Throwable throwable) { 32 | super(message, throwable); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/driver/UsageException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.driver; 25 | 26 | public final class UsageException extends RuntimeException { 27 | private final String message; 28 | 29 | public UsageException(final String message) { 30 | this.message = message; 31 | } 32 | 33 | public UsageException() { 34 | this.message = "Usage Error!" + "\n" + CLIBuilder.getOptions(); 35 | } 36 | 37 | @Override 38 | public String getMessage() { 39 | return message; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/driver/CLIBuilder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.driver; 25 | 26 | import org.apache.commons.cli.Options; 27 | 28 | public final class CLIBuilder { 29 | private static final Options OPTIONS = new Options(); 30 | 31 | static { 32 | // Defining command line options. 33 | OPTIONS.addOption("lT", "load-type", true, "Type of load to be generated"); 34 | OPTIONS.addOption("h", "help", false, "Usage information"); 35 | } 36 | 37 | private CLIBuilder() { 38 | } 39 | 40 | /** 41 | * Retrieve the command line options. 42 | * @return command line options. 43 | */ 44 | public static Options getOptions() { 45 | return OPTIONS; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/entities/ProcessorArchInfo.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.entities; 25 | 26 | public class ProcessorArchInfo { 27 | private final int numCores; 28 | private final int numThreadsPerCore; 29 | 30 | public ProcessorArchInfo(int numCores, int numThreadsPerCore) { 31 | this.numCores = numCores; 32 | this.numThreadsPerCore = numThreadsPerCore; 33 | } 34 | 35 | public int getNumCores() { 36 | return this.numCores; 37 | } 38 | 39 | public int getNumThreadsPerCore() { 40 | return this.numThreadsPerCore; 41 | } 42 | 43 | public String toString() { 44 | return "Processor Architecture Information\n--------------------------------\n" + "Total number of cores (num of cores per socket * num of sockets) = " + 45 | this.numCores + 46 | "\n" + 47 | "Number of threads per core = " + 48 | this.numThreadsPerCore + 49 | "\n"; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/util/ProcessorArch.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.util; 25 | 26 | import loadgenerator.entities.ProcessorArchInfo; 27 | 28 | import java.io.BufferedReader; 29 | import java.io.InputStreamReader; 30 | 31 | public class ProcessorArch { 32 | 33 | /** 34 | * Determine the following information about the underlying processor architecture, 35 | * 1. Number of cores 36 | * 2. Number of threads per core 37 | */ 38 | public static ProcessorArchInfo getProcessorArchInformation() throws Exception { 39 | Process p = Runtime.getRuntime().exec("lscpu"); 40 | BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); 41 | String line = ""; 42 | int numCores = 0; 43 | int numThreadsPerCore = 0; 44 | int numSockets = 0; 45 | int numCoresPerSocket = 0; 46 | while ((line = br.readLine()) != null) { 47 | if (line.contains("Socket(s):")) { 48 | // Retrieving the number of sockets 49 | String[] lineComponents = line.split("\\s+"); 50 | numSockets = Integer.parseInt(lineComponents[lineComponents.length - 1]); 51 | } else if (line.contains("Core(s) per socket:")) { 52 | // Retrieving the number of cores per socket. 53 | // Total number of cores would be NumCoresPerSocket * NumSockets 54 | String[] lineComponents = line.split("\\s+"); 55 | numCoresPerSocket = Integer.parseInt(lineComponents[lineComponents.length - 1]); 56 | } else if (line.contains("Thread(s) per core:")) { 57 | // Retrieving the number of threads per core. 58 | String[] lineComponents = line.split("\\s+"); 59 | numThreadsPerCore = Integer.parseInt(lineComponents[lineComponents.length - 1]); 60 | } 61 | } 62 | // Determining the total number of cores. 63 | numCores = numCoresPerSocket * numSockets; 64 | return new ProcessorArchInfo(numCores, numThreadsPerCore); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/util/LoadAverage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.util; 25 | 26 | import java.util.Random; 27 | import java.util.concurrent.ExecutorService; 28 | import java.util.concurrent.Callable; 29 | import java.util.concurrent.Future; 30 | import java.util.concurrent.Executors; 31 | import java.util.List; 32 | import java.util.ArrayList; 33 | import java.util.concurrent.ExecutionException; 34 | 35 | public class LoadAverage { 36 | 37 | /** 38 | * Creates load for the given amount of time. 39 | * @param numThreadsToCreate Number of threads to create so as to generate the required 1min load average. 40 | * @param duration Amount of time to maintain the load. 41 | */ 42 | public static void createLoad(int numThreadsToCreate, long duration) throws InterruptedException, ExecutionException { 43 | 44 | // Defining what each thread is going to execute. 45 | Callable task = () -> { 46 | long currentTime = System.currentTimeMillis(); 47 | // Run loop for specified duration. 48 | while (System.currentTimeMillis() < (currentTime + duration)) { 49 | double a = new Random().nextDouble(); 50 | double b = new Random().nextDouble(); 51 | double quot = a / b; 52 | } 53 | // Time is up! 54 | return "Task execution complete :)"; 55 | }; 56 | 57 | // Creating a list of callable tasks. 58 | List> callableTasks = new ArrayList<>(); 59 | for (int i = 0; i < numThreadsToCreate; i++) { 60 | callableTasks.add(task); 61 | } 62 | 63 | // Just rounding the potential number of threads to be created. 64 | ExecutorService taskExecutorService = Executors.newFixedThreadPool(numThreadsToCreate); 65 | // Execute all tasks. 66 | List> results = taskExecutorService.invokeAll(callableTasks); 67 | 68 | // Notifying the executor service that it is okay to shutdown once all tasks complete execution. 69 | taskExecutorService.shutdown(); 70 | 71 | for (Future result : results) { 72 | System.out.println(result.get()); 73 | } 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/driver/Driver.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.driver; 25 | 26 | import java.io.IOException; 27 | 28 | import org.apache.commons.cli.CommandLine; 29 | import org.apache.commons.cli.CommandLineParser; 30 | import org.apache.commons.cli.DefaultParser; 31 | import org.apache.commons.cli.HelpFormatter; 32 | import org.apache.commons.cli.ParseException; 33 | 34 | import loadgenerator.strategies.factory.SimpleStrategyFactoryI; 35 | import loadgenerator.strategies.factory.SimpleStrategyFactory; 36 | import loadgenerator.strategies.factory.UnsupportedLoadTypeException; 37 | import loadgenerator.strategies.LoadGenerationStrategyI; 38 | 39 | public class Driver { 40 | public static void main(final String[] args) { 41 | CommandLineParser commandLineParser = new DefaultParser(); 42 | CommandLine commandLine; 43 | // Parsing command line arguments. 44 | if (0 == args.length) { 45 | throw new UsageException(); 46 | } else { 47 | try { 48 | commandLine = commandLineParser.parse(CLIBuilder.getOptions(), args); 49 | } catch (ParseException e) { 50 | e.printStackTrace(); 51 | throw new UsageException(e.getMessage()); 52 | } 53 | } 54 | // Printing possible command line options and exiting. 55 | if (commandLine.hasOption("help")) { 56 | HelpFormatter helpFormatter = new HelpFormatter(); 57 | helpFormatter.printHelp("java -jar build/libs/system-load-generator-.jar [-h]" 58 | + " --load-type LOAD_TYPE", CLIBuilder 59 | .getOptions()); 60 | System.exit(0); 61 | } 62 | 63 | String loadType = commandLine.getOptionValue("load-type"); 64 | SimpleStrategyFactoryI factory = new SimpleStrategyFactory(); 65 | LoadGenerationStrategyI loadGenerationStrategy; 66 | try { 67 | loadGenerationStrategy = factory.getLoadGenerationStrategy(loadType); 68 | if (null != loadGenerationStrategy) { 69 | loadGenerationStrategy.execute(); 70 | } 71 | } catch (UnsupportedLoadTypeException | IOException exception) { 72 | exception.printStackTrace(); 73 | } 74 | 75 | System.out.println("DONE!"); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/strategies/ConstantCPULoad.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.strategies; 25 | 26 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 27 | import com.fasterxml.jackson.databind.ObjectMapper; 28 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 29 | import loadgenerator.entities.ProcessorArchInfo; 30 | import loadgenerator.util.CPULoad; 31 | import loadgenerator.util.ProcessorArch; 32 | 33 | import java.io.File; 34 | import java.io.IOException; 35 | 36 | public class ConstantCPULoad implements LoadGenerationStrategyI { 37 | // Setting default cpu load to be 50%. 38 | private static final double DEFAULT_CPU_LOAD = 0.5; 39 | // Setting default duration for the load to be 60sec. 40 | private static final int DEFAULT_DURATION = 60000; 41 | private static ProcessorArchInfo processorArchInfo = null; 42 | 43 | // Non-defaults. 44 | private double cpuLoad = DEFAULT_CPU_LOAD; 45 | private int duration = DEFAULT_DURATION; 46 | 47 | static { 48 | // Retrieving the processor architecture information 49 | try { 50 | processorArchInfo = ProcessorArch.getProcessorArchInformation(); 51 | } catch (Exception e) { 52 | System.err.println("failed to obtain processor architecture information."); 53 | e.printStackTrace(); 54 | } 55 | // Printing the processor architecture information 56 | System.out.println(processorArchInfo); 57 | } 58 | 59 | @JsonIgnoreProperties(ignoreUnknown = true) 60 | public static class Builder { 61 | private double cpuLoad = DEFAULT_CPU_LOAD; 62 | private int duration = DEFAULT_DURATION; 63 | 64 | public Builder withConfig(String configFilePath) throws IOException { 65 | ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); 66 | Builder builder; 67 | try { 68 | builder = mapper.readValue(new File(configFilePath), Builder.class); 69 | } catch (IOException exception) { 70 | throw new IOException("failed to open load generator config file", exception); 71 | } 72 | 73 | return builder; 74 | } 75 | 76 | public Builder() { } 77 | 78 | public void setCpuLoad(double cpuLoad) { 79 | this.cpuLoad = cpuLoad; 80 | } 81 | public void setDuration(int duration) { 82 | this.duration = duration; 83 | } 84 | 85 | public ConstantCPULoad build() { 86 | return new ConstantCPULoad(cpuLoad, duration); 87 | } 88 | } 89 | 90 | private ConstantCPULoad(double cpuLoad, int duration) { 91 | this.cpuLoad = cpuLoad; 92 | this.duration = duration; 93 | } 94 | 95 | // Generate constant CPU Load of the configured amount and maintain that 96 | // load for the configured duration. 97 | @Override 98 | public void execute() { 99 | System.out.println(String.format("Generating %f %% CPU load for %d seconds", 100 | cpuLoad, duration)); 101 | try { 102 | CPULoad.createLoad(processorArchInfo.getNumCores(), 103 | processorArchInfo.getNumThreadsPerCore(), 104 | cpuLoad, 105 | duration, 106 | false, 107 | 0); 108 | } catch (InterruptedException e) { 109 | System.err.println("threads generating constant cpu load interrupted!"); 110 | e.printStackTrace(); 111 | } 112 | System.out.println("Done generating CPU load!"); 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/strategies/factory/SimpleStrategyFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.strategies.factory; 25 | 26 | import java.io.IOException; 27 | import java.util.Objects; 28 | 29 | import loadgenerator.strategies.LoadGenerationStrategyI; 30 | import loadgenerator.strategies.ConstIncreaseCPULoad; 31 | import loadgenerator.strategies.ConstIncreaseLoadAverage; 32 | import loadgenerator.strategies.CPULoadGeneratorWithMemoryPressure; 33 | import loadgenerator.strategies.ConstantCPULoad; 34 | 35 | public final class SimpleStrategyFactory implements SimpleStrategyFactoryI { 36 | 37 | private enum LoadType { 38 | CPU_LOAD("cpuload", "cpuload_config.yaml"), 39 | LOAD_AVERAGE("loadaverage", "loadaverage_config.yaml"), 40 | CPU_LOAD_WITH_MEMORY_PRESSURE("cpuload_memorypressure", 41 | "cpuload_memorypressure_config.yaml"), 42 | CONSTANT_CPU_LOAD("const_cpuload", "const_cpuload_config.yaml"); 43 | 44 | private final String name; 45 | private final String configFilename; 46 | 47 | LoadType(final String s, final String configFilename) { 48 | name = s; 49 | this.configFilename = configFilename; 50 | } 51 | 52 | String getName() { 53 | return name; 54 | } 55 | 56 | String getConfigFilename() { 57 | return configFilename; 58 | } 59 | 60 | static boolean isValid(final String s) { 61 | for (LoadType loadType : values()) { 62 | if (loadType.getName().equals(s)) { 63 | return true; 64 | } 65 | } 66 | return false; 67 | } 68 | 69 | static LoadType forName(final String s) { 70 | for (LoadType loadType : values()) { 71 | if (loadType.getName().equals(s)) { 72 | return loadType; 73 | } 74 | } 75 | return null; 76 | } 77 | } 78 | 79 | private static final String PROJECT_ROOT = System.getProperty("user.dir"); 80 | private static final String CONFIGS_DIRECTORY = "configs"; 81 | 82 | @Override 83 | public LoadGenerationStrategyI getLoadGenerationStrategy(final String loadType) 84 | throws UnsupportedLoadTypeException, IOException { 85 | 86 | if (!LoadType.isValid(loadType)) { 87 | throw new UnsupportedLoadTypeException("failed to create load generation strategy: " 88 | + "unsupported load type"); 89 | } 90 | 91 | switch (Objects.requireNonNull(LoadType.forName(loadType))) { 92 | case CPU_LOAD: 93 | return new ConstIncreaseCPULoad.Builder() 94 | .withConfig(PROJECT_ROOT 95 | + "/" 96 | + CONFIGS_DIRECTORY 97 | + "/" 98 | + LoadType.CPU_LOAD.getConfigFilename()) 99 | .build(); 100 | case LOAD_AVERAGE: 101 | return new ConstIncreaseLoadAverage.Builder() 102 | .withConfig(PROJECT_ROOT 103 | + "/" 104 | + CONFIGS_DIRECTORY 105 | + "/" 106 | + LoadType.LOAD_AVERAGE.getConfigFilename()) 107 | .build(); 108 | case CPU_LOAD_WITH_MEMORY_PRESSURE: 109 | return new CPULoadGeneratorWithMemoryPressure.Builder() 110 | .withConfig(PROJECT_ROOT 111 | + "/" 112 | + CONFIGS_DIRECTORY 113 | + "/" 114 | + LoadType.CPU_LOAD_WITH_MEMORY_PRESSURE.getConfigFilename()) 115 | .build(); 116 | case CONSTANT_CPU_LOAD: 117 | return new ConstantCPULoad.Builder() 118 | .withConfig(PROJECT_ROOT 119 | + "/" 120 | + CONFIGS_DIRECTORY 121 | + "/" 122 | + LoadType.CONSTANT_CPU_LOAD.getConfigFilename()) 123 | .build(); 124 | default: 125 | return null; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/strategies/ConstIncreaseCPULoad.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.strategies; 25 | 26 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 27 | import com.fasterxml.jackson.databind.ObjectMapper; 28 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 29 | 30 | import java.io.File; 31 | import java.io.IOException; 32 | 33 | import loadgenerator.util.CPULoad; 34 | import loadgenerator.util.ProcessorArch; 35 | import loadgenerator.entities.ProcessorArchInfo; 36 | 37 | public class ConstIncreaseCPULoad implements LoadGenerationStrategyI { 38 | // Setting the default step size for increase in CPU load to be 10%. 39 | private static final double DEFAULT_STEP_SIZE = 0.1; 40 | // Setting default duration for the load to be 4sec. 41 | private static final int DEFAULT_DURATION = 4000; 42 | // Default number of segments for creating alternating CPU load. 43 | private static final int DEFAULT_ALT_SEGMENTS = 2; 44 | private static ProcessorArchInfo processorArchInfo = null; 45 | 46 | // Non-defaults. 47 | private double stepSize = DEFAULT_STEP_SIZE; 48 | private int duration = DEFAULT_DURATION; 49 | private boolean isAlt = false; 50 | private int segments = DEFAULT_ALT_SEGMENTS; 51 | 52 | static { 53 | // Retrieving the processor architecture information 54 | try { 55 | processorArchInfo = ProcessorArch.getProcessorArchInformation(); 56 | } catch (Exception e) { 57 | System.err.println("failed to obtain processor architecture information."); 58 | e.printStackTrace(); 59 | } 60 | // Printing the processor architecture information 61 | System.err.println(processorArchInfo); 62 | } 63 | 64 | public static class Builder { 65 | private double stepSize = DEFAULT_STEP_SIZE; 66 | private int duration = DEFAULT_DURATION; 67 | private boolean isAlt = false; 68 | 69 | private int segments = DEFAULT_ALT_SEGMENTS; 70 | 71 | public Builder withConfig(String configFilePath) throws IOException { 72 | ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); 73 | Builder builder; 74 | try { 75 | builder = mapper.readValue(new File(configFilePath), Builder.class); 76 | } catch (IOException exception) { 77 | throw new IOException("failed to open load generator config file", exception); 78 | } 79 | 80 | return builder; 81 | } 82 | 83 | public Builder() { 84 | } 85 | 86 | public void setStepSize(double stepSize) { 87 | this.stepSize = stepSize; 88 | } 89 | public void setDuration(int duration) { 90 | this.duration = duration; 91 | } 92 | public void setIsAlt(boolean isAlt) { 93 | this.isAlt = isAlt; 94 | } 95 | public void setSegments(int segments) { 96 | this.segments = segments; 97 | } 98 | 99 | public ConstIncreaseCPULoad build() { 100 | return new ConstIncreaseCPULoad(stepSize, duration, isAlt, segments); 101 | } 102 | 103 | } 104 | 105 | private ConstIncreaseCPULoad(double stepSize, int duration, boolean isAlt, int segments) { 106 | this.stepSize = stepSize; 107 | this.duration = duration; 108 | this.isAlt = isAlt; 109 | this.segments = segments; 110 | } 111 | 112 | // Constantly increase the CPU load in steps = stepSize. 113 | // The CPU load is going to be simulated for the specified duration. 114 | @Override 115 | public void execute() { 116 | // Time for each a particular CPU load needs to be maintained for. 117 | long currentTime = System.currentTimeMillis(); 118 | for (double load = stepSize; load <= 1.0; load += stepSize) { 119 | System.err.println("CPU load changing to " + load); 120 | try { 121 | CPULoad.createLoad(processorArchInfo.getNumCores(), 122 | processorArchInfo.getNumThreadsPerCore(), 123 | load, 124 | duration, 125 | isAlt, 126 | segments); 127 | } catch (InterruptedException e) { 128 | System.err.println("interrupted! Next load change will happen sooner than you think."); 129 | e.printStackTrace(); 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # System Load Generator 2 | Generate different kinds of system load. 3 | 4 | ## System Requirements 5 | 1. Java version 1.8+. 6 | 2. Gradle version 6.3. 7 | 8 | ### Compile 9 | Run `gradle build` to compile the source code. 10 | 11 | ### Run 12 | Run `gradle run` followed by command line arguments that you want to specify.
13 | The following command line arguments are supported. 14 | 1. `--help` - Display the help string. 15 | 2. `--load-type ` - Specify the type of load that you want to generate. The following are the supported types. 16 | - [cpuload](./src/main/java/loadgenerator/strategies/ConstIncreaseCPULoad.java) - CPU Load generator that 17 | constantly increases the CPU utilization of a machine from 1% to 100%. See [cpu-load-generator](#cpu-load-generator) for more information. 18 | - [loadaverage](./src/main/java/loadgenerator/strategies/ConstIncreaseLoadAverage.java) - 1min load average 19 | generate that constantly increases the load average. See [load-average-generator](#load-average-generator) for more information. 20 | - [cpuload_memorypressure](./src/main/java/loadgenerator/strategies/CPULoadGeneratorWithMemoryPressure.java) - 21 | Generate CPU load with memory pressure. See [cpu-load-generator-with-memory-pressure](#cpu-load-generator-with-memory-pressure) for more information. 22 | - [const_cpuload](./src/main/java/loadgenerator/strategies/ConstantCPULoad.java) - Generate constant CPU load for configured duration. See [constant-cpu-load](#constant-cpu-load-generator) for more information. 23 | 24 | ## Load Generators 25 | ### CPU Load Generator 26 | CPU Load generator that constantly increase the CPU utilization of a machine from 1% to 100%. 27 | Forked from [SriramKeerthi-Gist](https://gist.github.com/SriramKeerthi/0f1513a62b3b09fecaeb) and added functionality. 28 | 29 | #### Configuration 30 | The following are the configuration parameters that are provided in the YAML config file. The configuration file, named _cpuload\_config.yaml_, 31 | is to be stored in [configs](./configs) directory. 32 | 33 | * **stepSize** - TYPE: _decimal_ value in the range (0.0, 1.0). This specifies the increase in CPU load for every cycle. 34 | * **duration** - TYPE: _number_. This specifies the number of milliseconds for which the CPU load needs to be maintained for, before being increased again. 35 | * **isAlt** - TYPE: _boolean_. Consider a time slice to be 100ms. In the default state (when **isAlt** is *false*), CPU load is generated by making the current thread sleep for `(1 - load) * 100`ms. We could, however, generate the same CPU load with a different CPU usage pattern, such as an alternating one. When **isAlt** is *true*, CPU load is generated by making the current thread sleep multiple times, but for shorter durations, within the considered time slice (100ms). This leads to an alternating CPU usage pattern to create the same CPU load. 36 | * **segments** - TYPE: _number_. This specifies the number of times the CPU usage alternates, when **isAlt** is set to true. Suppose, the time slice is 100ms, and **segments** = 2, then to generate a CPU load of 50%, the thread would sleep twice for 25ms, once every 50ms. 37 | 38 | Below is a sample configuration for cpu load generator. 39 | ```yaml 40 | stepSize: 0.2 41 | duration: 3000 42 | isAlt: false 43 | segments: 2 44 | ``` 45 | 46 | ### Load Average Generator 47 | 48 | A 1-minute load average generator that constantly increases the load average for the past minute. 49 | 50 | #### Configuration 51 | The following are the configuration parameters that are provided in the YAML config file. The configuration file, named _loadaverage\_config.yaml_, 52 | is to be stored in [configs](./configs) directory. 53 | 54 | * **startLoadAverageCore** - TYPE: _decimal_ (default = 1/numCores). This specifies the starting value of 1min load average for a given core. This value signifies the number of processes that would be executed in the first minute. 55 | * **steSize** - TYPE: _decimal_ (default = 0.2). This specifies the increase in load average to be generated every minute. 56 | 57 | Below is a sample configuration for load average generator. 58 | ```yaml 59 | startLoadAverage: 0.25 # assuming quad-core machine. 60 | stepSize: 0.2 61 | ``` 62 | 63 | ### CPU Load Generator with Memory Pressure 64 | Generate CPU load with Memory pressure. 65 | 66 | #### Configuration 67 | The following are the configuration parameters that are provided in the YAML config file. The configuration file, named _cpuload\_memorypressure\_config.yaml_, 68 | is to be stored in [configs](./configs) directory. 69 | 70 | * **minCpuLoadPercentage** - Minimum CPU usage pressure. 71 | * **maxCpuLoadPercentage** - Maximum CPU usage pressure. 72 | * **ramUsageBytes** - RAM usage bytes. 73 | 74 | Below is a sample configuration for cpu load with memory pressure generator. 75 | ```yaml 76 | minCpuLoadPercentage: 0.2 77 | maxCpuLoadPercentage: 0.6 78 | ramUsageBytes: 2048 79 | ``` 80 | 81 | ### Constant CPU Load Generator 82 | CPU Load generator that generates a constant cpu load for a set duration. 83 | Wraps around [SriramKeerthi-Gist](https://gist.github.com/SriramKeerthi/0f1513a62b3b09fecaeb). 84 | 85 | #### Configuration 86 | The following are the configuration parameters that are provided in the YAML config file. The configuration file, named _const\_cpuload\_config.yaml_, 87 | is to be stored in [configs](./configs) directory. 88 | 89 | * **cpuLoad** - TYPE: _decimal_. This specifies the cpu load to generate. A `cpuLoad` of 1.0 indicates 100% cpu load. 90 | * **duration** - TYPE: _number_. This specifies the number of milliseconds for which the CPU load needs to be maintained. 91 | 92 | Below is a sample configuration for cpu load generator. 93 | ```yaml 94 | cpuLoad: 0.6 95 | duration: 70000 96 | ``` 97 | 98 | ## Docker 99 | System Load Generator can be run in a docker container using the below command. 100 | ```commandline 101 | docker run -t pkaushi1/system-load-generator:v2 [-h | --load-type=LOAD_TYPE] 102 | ``` 103 | Note that this will use the default configuration (see [configs](./configs)) for each load generation strategy. 104 | 105 | To use a different configuration, update the corresponding file in [configs](./configs) and then bindmount it to the 106 | _configs/_ directory within the container using the command given below. 107 | ```commandline 108 | docker run -v $PWD/configs:/configs -t pkaushi1/system-load-generator:v2 [-h | --load-type=LOAD_TYPE] 109 | ``` 110 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/strategies/ConstIncreaseLoadAverage.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.strategies; 25 | 26 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 27 | import com.fasterxml.jackson.databind.ObjectMapper; 28 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 29 | 30 | import java.io.File; 31 | import java.io.IOException; 32 | 33 | import loadgenerator.util.LoadAverage; 34 | import loadgenerator.util.ProcessorArch; 35 | import loadgenerator.entities.ProcessorArchInfo; 36 | 37 | import java.util.concurrent.ExecutionException; 38 | 39 | public class ConstIncreaseLoadAverage implements LoadGenerationStrategyI { 40 | // Default value for 1min load average on each core. 41 | // This means that we would start with (START_LOAD_AVERAGE_CORE * numCores) number of threads to be always running. 42 | private static final double START_LOAD_AVERAGE_CORE; 43 | 44 | // Setting default step size for load average to be 20%. 45 | // This means that every minute, the number of running threads would be increased by (0.2 * numCores). 46 | // For example, on a 10 core machine, 47 | // There would be 0 thread running in the first minute. 48 | // There would be 2 threads running in parallel in the second minute. 49 | // There would be 4 threads running in parallel in the third minut and so on. 50 | private static final double STEP_SIZE = 0.2; 51 | 52 | // Setting default final value for 1min load average for each core to be 10 (total 1min load_avg = 10 * numCores). 53 | // This means that load would be increased until there are 10 processes either running or waiting to be run on 54 | // each core for the minute. 55 | private static final double LOAD_AVERAGE_LIMIT_CORE = 10.0; 56 | 57 | // Information regarding the number of cores and the number of virtual CPUs available. 58 | private static ProcessorArchInfo procArchInfo = null; 59 | 60 | // Non-Defaults. 61 | private final double startLoadAvgCore; 62 | private final double stepSize; 63 | 64 | static { 65 | // Retrieving the processor architecture information. 66 | try { 67 | procArchInfo = ProcessorArch.getProcessorArchInformation(); 68 | } catch (Exception e) { 69 | System.err.println("failed to obtain processor architecture information."); 70 | e.printStackTrace(); 71 | } 72 | // Printing the processor architecture information. 73 | System.err.println(procArchInfo); 74 | 75 | // Initializing default value for START_LOAD_AVERAGE_CORE. 76 | START_LOAD_AVERAGE_CORE = 1.0 / procArchInfo.getNumCores(); 77 | } 78 | 79 | @JsonIgnoreProperties(ignoreUnknown = true) 80 | public static class Builder { 81 | private double startLoadAvgCore = START_LOAD_AVERAGE_CORE; 82 | private double stepSize = STEP_SIZE; 83 | 84 | public Builder withConfig(String configFilePath) throws IOException { 85 | ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); 86 | Builder builder; 87 | try { 88 | builder = mapper.readValue(new File(configFilePath), Builder.class); 89 | } catch (IOException exception) { 90 | throw new IOException("failed to open load average generator config file", exception); 91 | } 92 | 93 | return builder; 94 | } 95 | 96 | public Builder() { 97 | } 98 | 99 | public void setStepSize(double stepSize) { this.stepSize = stepSize; } 100 | public void setStartLoadAvgCore(double startLoadAvgCore) { this.startLoadAvgCore = startLoadAvgCore; } 101 | 102 | public ConstIncreaseLoadAverage build() { 103 | return new ConstIncreaseLoadAverage(startLoadAvgCore, stepSize); 104 | } 105 | } 106 | 107 | private ConstIncreaseLoadAverage(double startLoadAvgCore, double stepSize) { 108 | this.startLoadAvgCore = startLoadAvgCore; 109 | this.stepSize = stepSize; 110 | } 111 | 112 | @Override 113 | public void execute() { 114 | long duration = 60000; // 1min. 115 | long currentTime = System.currentTimeMillis(); 116 | double currentLoadAvgCore = startLoadAvgCore; 117 | while (currentLoadAvgCore <= LOAD_AVERAGE_LIMIT_CORE) { 118 | int totalNumCores = procArchInfo.getNumCores(); 119 | int numThreadsToCreate = (int) Math.floor((currentLoadAvgCore * totalNumCores) + 0.5); 120 | System.out.println("Creating load..."); 121 | System.out.println("load average for next minute = " + numThreadsToCreate); 122 | System.out.println(); 123 | 124 | try { 125 | // Only if positive load. 126 | if (currentLoadAvgCore != 0) { 127 | LoadAverage.createLoad(numThreadsToCreate, duration); 128 | } 129 | // Thread.sleep(duration); 130 | } catch (InterruptedException | ExecutionException ie) { 131 | System.err.println((duration / 1000) + "second wait bas been interrupted!" 132 | + "Next load change will happen sooner than you think."); 133 | } 134 | currentLoadAvgCore += stepSize; 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/strategies/CPULoadGeneratorWithMemoryPressure.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.strategies; 25 | 26 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 27 | import com.fasterxml.jackson.databind.ObjectMapper; 28 | import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; 29 | 30 | import java.io.File; 31 | import java.io.IOException; 32 | import java.util.Locale; 33 | import java.util.Random; 34 | 35 | import loadgenerator.util.ProcessorArch; 36 | import loadgenerator.entities.ProcessorArchInfo; 37 | 38 | public class CPULoadGeneratorWithMemoryPressure implements LoadGenerationStrategyI { 39 | 40 | private final int minCpuLoadPercentage; 41 | private final int maxCpuLoadPercentage; 42 | private final int ramUsageBytes; 43 | 44 | @JsonIgnoreProperties(ignoreUnknown = true) 45 | public static class Builder { 46 | private int minCpuLoadPercentage; 47 | private int maxCpuLoadPercentage; 48 | private int ramUsageBytes; 49 | 50 | public Builder withConfig(String configFilePath) throws IOException { 51 | ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); 52 | Builder builder; 53 | try { 54 | builder = mapper.readValue(new File(configFilePath), Builder.class); 55 | } catch (IOException exception) { 56 | throw new IOException("failed to open cpu load with memory pressure generator config file", exception); 57 | } 58 | 59 | return builder; 60 | } 61 | 62 | public Builder() { 63 | } 64 | 65 | public void setMinCpuLoadPercentage(int minCpuLoadPercentage) { 66 | this.minCpuLoadPercentage = minCpuLoadPercentage; 67 | } 68 | public void setMaxCpuLoadPercentage(int maxCpuLoadPercentage) { 69 | this.maxCpuLoadPercentage = maxCpuLoadPercentage; 70 | } 71 | public void setRamUsageBytes(int ramUsageBytes) { 72 | this.ramUsageBytes = ramUsageBytes; 73 | } 74 | 75 | public CPULoadGeneratorWithMemoryPressure build() { 76 | return new CPULoadGeneratorWithMemoryPressure(minCpuLoadPercentage, maxCpuLoadPercentage, ramUsageBytes); 77 | } 78 | } 79 | 80 | private CPULoadGeneratorWithMemoryPressure(int minCpuLoadPercentage, int maxCpuLoadPercentage, int ramUsageBytes) { 81 | this.minCpuLoadPercentage = minCpuLoadPercentage; 82 | this.maxCpuLoadPercentage = maxCpuLoadPercentage; 83 | this.ramUsageBytes = ramUsageBytes; 84 | 85 | } 86 | 87 | @Override 88 | public void execute() { 89 | ProcessorArchInfo procArchInfo = null; 90 | try { 91 | procArchInfo = ProcessorArch.getProcessorArchInformation(); 92 | } catch (Exception e) { 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | 97 | int numCores = procArchInfo.getNumThreadsPerCore(); 98 | int numThreadsPerCore = procArchInfo.getNumThreadsPerCore(); 99 | int threadsToCreate = numCores * numThreadsPerCore; 100 | 101 | byte[] memory = new byte[ramUsageBytes / threadsToCreate]; 102 | for (int thread = 0; thread < threadsToCreate; thread++) { 103 | new BusyThread("Thread-" + thread, minCpuLoadPercentage, maxCpuLoadPercentage, memory).start(); 104 | } 105 | } 106 | 107 | /** 108 | * Thread that actually generates the given load 109 | * @author Sriram 110 | */ 111 | private static class BusyThread extends Thread { 112 | private final Random random; 113 | private final int minCpuLoadPercentage; 114 | private final int maxCpuLoadPercentage; 115 | private final byte[] memory; 116 | 117 | public BusyThread(String name, int minCpuLoadPercentage, int maxCpuLoadPercentage, byte[] memory) { 118 | super(name); 119 | 120 | this.random = new Random(name.hashCode() + System.currentTimeMillis()); 121 | this.minCpuLoadPercentage = minCpuLoadPercentage; 122 | this.maxCpuLoadPercentage = maxCpuLoadPercentage; 123 | this.memory = memory; 124 | } 125 | 126 | /** 127 | * Generates the load when run 128 | */ 129 | @Override 130 | public void run() { 131 | 132 | final int cpuPressureRange = maxCpuLoadPercentage - minCpuLoadPercentage; 133 | 134 | try { 135 | System.out.println(String.format(Locale.US, "Thread %s starting with CPU pressure [%d-%d] and %d bytes", 136 | getName(), minCpuLoadPercentage, maxCpuLoadPercentage, memory.length)); 137 | Thread.sleep(cpuPressureRange); 138 | 139 | while (true) { 140 | final int duration = minCpuLoadPercentage + random.nextInt(cpuPressureRange); 141 | final long startTime = System.currentTimeMillis(); 142 | long currentDuration = (System.currentTimeMillis() - startTime); 143 | while (currentDuration < duration) { 144 | final int cellToAccess = random.nextInt(memory.length); 145 | final byte previousValue = memory[cellToAccess]; 146 | memory[cellToAccess] = (byte) (previousValue + 1); 147 | 148 | currentDuration = (System.currentTimeMillis() - startTime); 149 | } 150 | if (currentDuration > 100) { 151 | currentDuration = 100; 152 | } 153 | Thread.sleep(100 - currentDuration); 154 | } 155 | } catch (InterruptedException e) { 156 | System.out.println(String.format(Locale.US, "Thread %s failed with %s", getName(), e.getMessage())); 157 | e.printStackTrace(); 158 | } 159 | } 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/loadgenerator/util/CPULoad.java: -------------------------------------------------------------------------------- 1 | /** 2 | * MIT License 3 | *

4 | * Copyright (c) 2019 PRADYUMNA KAUSHIK 5 | *

6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | *

13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | *

16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package loadgenerator.util; 25 | 26 | import java.util.List; 27 | import java.util.ArrayList; 28 | 29 | /** 30 | * Generates Load on the CPU by keeping it busy for the given load percentage 31 | * @author Sriram 32 | * @author Pradyumna Kaushik 33 | */ 34 | public class CPULoad { 35 | /** 36 | * Function to be called by a wrapper 37 | * A wrapper could be a program that determines the requirements such as, 38 | * Number of cores 39 | * Number of threads per core, etc 40 | * The wrapper would then pass those values so as to be able to create the requried amount of load. 41 | * @param numCore Number of cores 42 | * @param numThreadsPerCore Number of threads per core 43 | * @param load % CPU load to generate 44 | * @param duration Duration for which this load has to be maintained 45 | * @param isAlt Whether we need to create an alternating load. An alternating load is one where we 46 | * alternate between running and sleeping, within the load duration, to generate the required CPU load. 47 | * @param segments Number of alternating segments, for an alternating CPU load, for the specified duration. 48 | */ 49 | public static void createLoad(int numCore, int numThreadsPerCore, double load, 50 | long duration, boolean isAlt, int segments) throws InterruptedException { 51 | List threads = new ArrayList<>(); 52 | if (isAlt) { 53 | for (int thread = 0; thread < numCore * numThreadsPerCore; thread++) { 54 | threads.add(new AltBusyThread("Thread" + thread, load, duration, segments)); 55 | } 56 | } else { 57 | for (int thread = 0; thread < numCore * numThreadsPerCore; thread++) { 58 | threads.add(new BusyThread("Thread" + thread, load, duration)); 59 | } 60 | } 61 | 62 | // starting threads. 63 | for (Thread thread : threads) { 64 | thread.start(); 65 | } 66 | 67 | // waiting for all threads to complete. 68 | for (Thread thread : threads) { 69 | thread.join(); // throws InterruptedException. 70 | } 71 | } 72 | 73 | /** 74 | * Thread that actually generates the given load 75 | * @author Sriram 76 | */ 77 | private static class BusyThread extends Thread { 78 | private final double load; 79 | private final long duration; 80 | 81 | /** 82 | * Constructor which creates the thread 83 | * @param name Name of this thread 84 | * @param load Load % that this thread should generate 85 | * @param duration Duration that this thread should generate the load for 86 | */ 87 | public BusyThread(String name, double load, long duration) { 88 | super(name); 89 | this.load = load; 90 | this.duration = duration; 91 | } 92 | 93 | /** 94 | * Generates the load when run 95 | */ 96 | @Override 97 | public void run() { 98 | long startTime = System.currentTimeMillis(); 99 | try { 100 | // Loop for the given duration 101 | long currentTime = System.currentTimeMillis(); 102 | while ((currentTime - startTime) < duration) { 103 | // Every 100ms, sleep for the percentage of unladen time 104 | if ((currentTime % 100) == 0) { 105 | Thread.sleep((long) Math.floor((1 - load) * 100)); 106 | } 107 | currentTime = System.currentTimeMillis(); 108 | } 109 | } catch (InterruptedException e) { 110 | e.printStackTrace(); 111 | } 112 | } 113 | } 114 | 115 | /** 116 | * Thread that generates the given load by alternating between running state and sleep state 117 | * @author Pradyumna Kaushik 118 | */ 119 | private static class AltBusyThread extends Thread { 120 | private final double load; 121 | private final long duration; 122 | // Number of times the thread needs to switch to sleep state 123 | // This also represents the number of pairs of Busy:Sleep for this thread. 124 | private final int segments; 125 | 126 | /** 127 | * Constructor which creates the thread 128 | * @param name Name of this thread 129 | * @param load Load % that this thread should generate 130 | * @param duration Duration that this thread should generate the load for 131 | */ 132 | public AltBusyThread(String name, double load, long duration, int segments) { 133 | super(name); 134 | this.load = load; 135 | this.duration = duration; 136 | this.segments = segments; 137 | } 138 | 139 | /** 140 | * Generates the load when run 141 | */ 142 | @Override 143 | public void run() { 144 | long startTime = System.currentTimeMillis(); 145 | try { 146 | // Loop for the given duration. 147 | long currentTime = System.currentTimeMillis(); 148 | while ((currentTime - startTime) < duration) { 149 | // We create alternating CPU utilizations in every 100ms. 150 | // The number of segments would determine the granularity. 151 | // Note that this approach would work well when the number of segments divides 100. 152 | long segmentInterval = (long) Math.floor(100.0 / this.segments); 153 | if ((currentTime % segmentInterval) == 0) { 154 | // Sleep for (segmentInterval)*(1 - load) milliseconds. 155 | long sleepFor = (long) Math.floor(segmentInterval * (1 - this.load)); 156 | Thread.sleep(sleepFor); 157 | } 158 | currentTime = System.currentTimeMillis(); 159 | } 160 | } catch (InterruptedException e) { 161 | e.printStackTrace(); 162 | } 163 | } 164 | } 165 | } 166 | --------------------------------------------------------------------------------