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

Adding stress test script #261

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Adding stress test script #261

wants to merge 6 commits into from

Conversation

dwang3851
Copy link

@dwang3851 dwang3851 commented Oct 27, 2024

Adds a script for basic stress test functionality. This script uses the Tango CLI to simulate various submissions scenarios. The number of submissions can be adjusted as well as the rate at which they are submitted. Required parameters include the autograder image, the path to the Tango directory, the job name, and the path to the job.

Example command to run script:

  • python3 stressTest.py --num_submissions 10 --submission_delay 1.0 --autograder_image autograding_image_py --tango_port 4567 --tango_path ~/Tango --job_name assessment1 --job_path ~/Tango/clients/job1/

To get metrics, simply add --get_metrics True to the end of this command, this will not spawn any new jobs.

@dwang3851 dwang3851 requested a review from a team October 27, 2024 17:57
@dwang3851 dwang3851 self-assigned this Oct 27, 2024
@dwang3851 dwang3851 requested review from KesterTan and removed request for a team October 27, 2024 17:57
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (6)
clients/job11/autograde-Makefile (1)

1-3: Consider adding documentation and phony targets

To improve maintainability and prevent conflicts with similarly named files:

Add these improvements:

+.PHONY: all clean
+
+# Extract archive and run driver script
 all:
 	tar xvf autograde.tar
 	(cd random; ./driver.sh)
+
+# Clean up extracted files
+clean:
+	rm -rf random
clients/job11/maxsubarray.py (2)

1-11: Add documentation and type hints for better code clarity.

The implementation of Kadane's algorithm is correct, but could benefit from better documentation and type safety.

Here's a suggested improvement:

-def maxsubarray(nums):
+from typing import List
+
+def maxsubarray(nums: List[int]) -> int:
+    """Calculate the maximum sum of any contiguous subarray within the given array.
+    
+    Args:
+        nums: List of integers
+        
+    Returns:
+        Maximum sum of any contiguous subarray
+        
+    Raises:
+        ValueError: If the input list is empty
+    """
     n = len(nums)
+    if not nums:
+        raise ValueError("Input array cannot be empty")
     if n == 1:
         return nums[0]
-    lookup = [0] * n
-    lookup[0] = nums[0]
+    max_ending_here = [0] * n  # tracks max sum ending at each position
+    max_ending_here[0] = nums[0]
     res = nums[0]
     for i in range(1, n):
-        lookup[i] = max(lookup[i-1]+nums[i], nums[i])
-        res = max(res, lookup[i])
+        max_ending_here[i] = max(max_ending_here[i-1]+nums[i], nums[i])
+        res = max(res, max_ending_here[i])
     return res

1-11: Consider adding test cases.

Since this file is part of a job directory that will be used for stress testing, it would be beneficial to include test cases to verify the implementation.

Would you like me to help generate a test suite that covers various scenarios including:

  • Empty array
  • Single element array
  • Array with all negative numbers
  • Array with mixed positive and negative numbers
  • Array with all positive numbers
stressTest.py (1)

1-76: Consider security and performance implications.

The stress testing script could potentially impact system stability and security. Consider implementing:

  1. Rate limiting protection to prevent accidental DoS
  2. Authentication checks before allowing stress tests
  3. Resource monitoring (CPU, memory, disk) during tests
  4. Maximum test duration limits
  5. Cleanup of temporary files

Would you like assistance in implementing these safety measures?

🧰 Tools
🪛 Ruff

29-29: Comparison to None should be cond is None

Replace with cond is None

(E711)

worker.py (2)

323-324: Consider enhancing timing metrics for comprehensive stress testing.

While the elapsed time logging is valuable for successful jobs, consider these enhancements to better support stress testing:

  1. Add timing information for failed jobs to understand failure patterns
  2. Include detailed timing breakdowns for each phase (VM setup, copy in/out, job execution)
  3. Consider adding timing metrics to the job trace for historical analysis

Here's a suggested enhancement:

 elapsed_secs = time.time() - start_time
-self.log.info("Success: job %s:%d finished after %d seconds" % (self.job.name, self.job.id, elapsed_secs))
+timing_msg = "Job %s:%d completed in %d seconds (status: %s)" % (
+    self.job.name, self.job.id, elapsed_secs,
+    "success" if all(r == 0 for r in ret.values()) else "failed"
+)
+self.log.info(timing_msg)
+self.job.appendTrace("%s|%s" % (datetime.now().ctime(), timing_msg))

This enhancement:

  • Logs timing for all jobs, not just successful ones
  • Adds timing to job trace for historical analysis
  • Clearly indicates job status alongside timing

Line range hint 162-324: Consider implementing structured metrics collection.

To better support stress testing and performance analysis, consider implementing a dedicated metrics collection system that could:

  1. Track detailed timing breakdowns for each phase (VM setup, copy in/out, job execution)
  2. Collect system resource metrics (CPU, memory, network usage)
  3. Store metrics in a structured format for easier analysis
  4. Support aggregation of metrics across multiple worker instances

This would provide more comprehensive data for stress testing analysis and system optimization.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 92ae12f and ad2dcdf.

⛔ Files ignored due to path filters (2)
  • clients/job11/autograde.tar is excluded by !**/*.tar, !**/*.tar
  • pyvenv.cfg is excluded by !**/*.cfg
📒 Files selected for processing (5)
  • .gitignore (1 hunks)
  • clients/job11/autograde-Makefile (1 hunks)
  • clients/job11/maxsubarray.py (1 hunks)
  • stressTest.py (1 hunks)
  • worker.py (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .gitignore
🧰 Additional context used
🪛 Ruff
stressTest.py

29-29: Comparison to None should be cond is None

Replace with cond is None

(E711)

🔇 Additional comments (5)
clients/job11/autograde-Makefile (2)

1-3: Verify integration with stress testing script

Since this Makefile is part of a PR adding stress testing functionality, we should ensure it works correctly with the stress test script.

Let's check how this job is referenced in the stress test script:

#!/bin/bash
# Search for references to job11 or this Makefile in the stress test script
rg -l "job11|autograde-Makefile" 

1-3: ⚠️ Potential issue

Add error handling and improve security measures

The current implementation has several potential issues:

  1. No error handling for missing files or failed commands
  2. No validation of extracted contents
  3. No cleanup of temporary files

Consider applying these improvements:

all:
-	tar xvf autograde.tar
-	(cd random; ./driver.sh)
+	@if [ ! -f autograde.tar ]; then \
+		echo "Error: autograde.tar not found"; \
+		exit 1; \
+	fi
+	@echo "Extracting autograde.tar..."
+	@tar xf autograde.tar
+	@if [ ! -d random ] || [ ! -x random/driver.sh ]; then \
+		echo "Error: Invalid archive contents or missing driver.sh"; \
+		exit 1; \
+	fi
+	@echo "Running driver script..."
+	@(cd random && ./driver.sh)
+	@echo "Cleaning up..."
+	@rm -rf random

Changes made:

  • Added existence checks for required files
  • Added validation of extracted contents
  • Added cleanup after execution
  • Reduced verbosity of tar extraction
  • Added error messages
  • Made commands quiet with @ prefix

Let's verify the structure of the archive and the driver script:

clients/job11/maxsubarray.py (1)

1-11: Verify numeric input validation.

The current implementation assumes all elements in the input list are numbers. Consider adding runtime type checking if this will be used in a testing environment.

Let's check if there are any input validation patterns used in other job directories:

stressTest.py (1)

1-7: LGTM! Clean and well-organized imports.

The imports are properly organized with system modules first, followed by local modules.

worker.py (1)

162-162: LGTM: Appropriate timing implementation.

The addition of start_time tracking is well-placed to capture the complete job execution duration, supporting the stress testing functionality.

stressTest.py Outdated Show resolved Hide resolved
stressTest.py Outdated Show resolved Hide resolved
stressTest.py Outdated Show resolved Hide resolved
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between ad2dcdf and b186419.

📒 Files selected for processing (2)
  • .gitignore (1 hunks)
  • stressTest.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .gitignore
🧰 Additional context used
🪛 Ruff
stressTest.py

46-46: Comparison to None should be cond is None

Replace with cond is None

(E711)

stressTest.py Show resolved Hide resolved
stressTest.py Show resolved Hide resolved
stressTest.py Outdated Show resolved Hide resolved
@20wildmanj 20wildmanj requested review from jhs-panda and removed request for KesterTan October 31, 2024 19:24
@autolab autolab deleted a comment from coderabbitai bot Nov 3, 2024
Copy link

coderabbitai bot commented Nov 3, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

The changes introduced in this pull request consist of the addition of a new script, stressTest.py, which facilitates stress testing using the Tango framework. This script includes two main functions: run_stress_test, which submits jobs to the Tango CLI, and get_metrics, which retrieves job completion metrics from a log file. Additionally, the worker.py file has been updated to enhance logging and error handling within the Worker class, improving the tracking of job execution and failure scenarios.

Changes

File Change Summary
stressTest.py Introduced a new script with two functions: run_stress_test for submitting jobs with parameters and logging, and get_metrics for retrieving job completion metrics from a log file. Includes command-line argument parsing.
worker.py Enhanced logging and error handling in the Worker class. Added start_time for tracking job duration, improved error logging in rescheduleJob, and refined exception handling in notifyServer.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant StressTest
    participant TangoCLI
    participant LogFile

    User->>StressTest: run_stress_test(params)
    StressTest->>TangoCLI: submit job
    TangoCLI-->>StressTest: job submission result
    StressTest->>LogFile: log job metrics
    User->>StressTest: get_metrics(output_file)
    StressTest->>LogFile: read job completion metrics
    LogFile-->>StressTest: return metrics
    StressTest-->>User: output metrics
Loading

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 128c252 and 6fb153d.

📒 Files selected for processing (1)
  • worker.py (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • worker.py

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's limits when posting large numbers of comments.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (4)
worker.py (3)

162-162: LGTM! Consider enhancing timing granularity.

The addition of execution timing is valuable for stress testing. However, consider tracking individual operation timings (waitVM, copyIn, runJob, copyOut) to provide more detailed performance insights.

 def run(self):
     try:
+        operation_times = {}
         start_time = time.time()
         ret = {}
         # ... existing code ...
         
         ret["waitvm"] = self.vmms.waitVM(vm, Config.WAITVM_TIMEOUT)
+        operation_times["waitvm"] = time.time() - start_time
         
         # ... existing code ...
         
         ret["copyin"] = self.vmms.copyIn(vm, self.job.input)
+        operation_times["copyin"] = time.time() - operation_times.get("waitvm", start_time)
         
         # ... existing code ...
         
         elapsed_secs = time.time() - start_time
         self.log.info(
-            "Success: job %s:%d finished after %d seconds"
-            % (self.job.name, self.job.id, elapsed_secs)
+            "Success: job %s:%d finished after %d seconds (waitVM: %.2fs, copyIn: %.2fs, ...)"
+            % (self.job.name, self.job.id, elapsed_secs, 
+               operation_times.get("waitvm", 0), operation_times.get("copyin", 0))
         )

Also applies to: 323-327


379-379: LGTM! Consider enhancing error logging.

The VM detachment error handling is correct, but could benefit from additional logging to track VM lifecycle during error scenarios.

-                self.detachVM(return_vm=False, replace_vm=True)
+                self.log.error("Detaching VM %s due to error: %s" % 
+                    (self.vmms.instanceName(vm.id, vm.name), str(err)))
+                try:
+                    self.detachVM(return_vm=False, replace_vm=True)
+                    self.log.info("Successfully detached and replaced VM %s" % 
+                        self.vmms.instanceName(vm.id, vm.name))
+                except Exception as e:
+                    self.log.error("Failed to detach VM %s: %s" % 
+                        (self.vmms.instanceName(vm.id, vm.name), str(e)))

Line range hint 162-379: Overall changes effectively support stress testing objectives.

The addition of timing metrics and enhanced error handling align well with the PR's goal of implementing stress testing functionality. The timing information will be valuable for analyzing system performance under load, while the improved error handling ensures system stability during stress tests.

Consider adding the following metrics to enhance stress test analysis:

  • VM allocation/deallocation timing
  • Queue wait times
  • Resource utilization stats (CPU, memory)
  • Error rate tracking
stressTest.py (1)

56-58: Use a non-zero exit code when an error occurs

When Config.LOGFILE is None, the program prints an error message and exits with code 0, indicating success. It should exit with a non-zero exit code to signal that an error occurred.

Update the code to reflect the error status:

 if Config.LOGFILE is None:
     print("Make sure logs are recorded in a log file")
-    sys.exit(0)
+    sys.exit(1)
🛑 Comments failed to post (2)
stressTest.py (2)

52-52: 🛠️ Refactor suggestion

Avoid using sys.exit within functions

It's recommended to avoid calling sys.exit(0) inside the run_stress_test function. Instead, let the function return control to the caller, possibly with a status code or result. This improves modularity and allows the caller to decide how to handle the program flow.

Apply this diff to modify the function:

 def run_stress_test(
     num_submissions,
     submission_delay,
     autograder_image,
     output_file,
     tango_port,
     tango_path,
     job_name,
     job_path,
 ):
     ...
-    sys.exit(0)
+    return

And update the main block to handle the exit:

 if __name__ == "__main__":
     ...
     if args.get_metrics:
         get_metrics(args.output_file)
     else:
         run_stress_test(
             args.num_submissions,
             args.submission_delay,
             args.autograder_image,
             args.output_file,
             args.tango_port,
             args.tango_path,
             args.job_name,
             args.job_path,
         )
+    sys.exit(0)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

    return

76-76: 🛠️ Refactor suggestion

Avoid using sys.exit within functions

Similarly, avoid calling sys.exit(0) inside the get_metrics function. Allow the function to return to the caller, enabling better control over the program's flow.

Modify the function as follows:

 def get_metrics(output_file):
     ...
-    sys.exit(0)
+    return

And update the main block accordingly:

 if __name__ == "__main__":
     ...
     if args.get_metrics:
         get_metrics(args.output_file)
+        sys.exit(0)
     else:
         run_stress_test(
             args.num_submissions,
             args.submission_delay,
             args.autograder_image,
             args.output_file,
             args.tango_port,
             args.tango_path,
             args.job_name,
             args.job_path,
         )
+        sys.exit(0)

Copy link

@jhs-panda jhs-panda left a comment

Choose a reason for hiding this comment

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

Functionality works, just some nitpicks on how information is displayed/clarifying error messages. May also help to add some more screenshots to description of PR to make it clear to viewer how to use stress test + what results could look like.

stressTest.py Show resolved Hide resolved
stressTest.py Show resolved Hide resolved
stressTest.py Show resolved Hide resolved
stressTest.py Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants